2019-07-04 17:14:51 +02:00
/*
2021-01-05 11:58:19 +01:00
* Copyright ( C ) 2019 - 2021 Intel Corporation
2019-07-04 17:14:51 +02:00
*
* SPDX - License - Identifier : MIT
*
*/
2021-01-19 17:29:20 +01:00
# include "shared/source/device_binary_format/elf/zebin_elf.h"
2020-02-23 22:44:01 +01:00
# include "shared/source/helpers/ptr_math.h"
2020-07-14 16:44:28 +02:00
# include "shared/source/memory_manager/graphics_allocation.h"
2020-10-08 14:31:53 +02:00
# include "shared/source/program/program_initialization.h"
2021-01-21 13:10:13 +01:00
# include "shared/test/common/helpers/debug_manager_state_restore.h"
# include "shared/test/common/helpers/default_hw_info.h"
# include "shared/test/common/mocks/mock_elf.h"
# include "shared/test/common/mocks/mock_graphics_allocation.h"
2020-07-14 16:44:28 +02:00
2020-10-07 15:32:03 +02:00
# include "opencl/test/unit_test/mocks/mock_cl_device.h"
2020-10-08 14:31:53 +02:00
# include "opencl/test/unit_test/mocks/mock_svm_manager.h"
2020-01-11 18:25:26 +01:00
# include "RelocationInfo.h"
2019-07-04 17:14:51 +02:00
# include "gmock/gmock.h"
# include "gtest/gtest.h"
# include "linker_mock.h"
# include <string>
2020-01-11 18:25:26 +01:00
TEST ( SegmentTypeTests , givenSegmentTypeWhenAsStringIsCalledThenProperRepresentationIsReturned ) {
EXPECT_STREQ ( " UNKOWN " , NEO : : asString ( NEO : : SegmentType : : Unknown ) ) ;
EXPECT_STREQ ( " GLOBAL_CONSTANTS " , NEO : : asString ( NEO : : SegmentType : : GlobalConstants ) ) ;
EXPECT_STREQ ( " GLOBAL_VARIABLES " , NEO : : asString ( NEO : : SegmentType : : GlobalVariables ) ) ;
EXPECT_STREQ ( " INSTRUCTIONS " , NEO : : asString ( NEO : : SegmentType : : Instructions ) ) ;
}
TEST ( LinkerInputTraitsTests , whenPointerSizeNotSizeThenDefaultsToHostPointerSize ) {
using PointerSize = NEO : : LinkerInput : : Traits : : PointerSize ;
auto expectedPointerSize = ( sizeof ( void * ) = = 4 ) ? PointerSize : : Ptr32bit : PointerSize : : Ptr64bit ;
auto pointerSize = NEO : : LinkerInput : : Traits { } . pointerSize ;
EXPECT_EQ ( expectedPointerSize , pointerSize ) ;
}
2019-07-04 17:14:51 +02:00
TEST ( LinkerInputTests , givenGlobalsSymbolTableThenProperlyDecodesGlobalVariablesAndGlobalConstants ) {
NEO : : LinkerInput linkerInput ;
2020-01-11 18:25:26 +01:00
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
vISA : : GenSymEntry entry [ 2 ] = { { } , { } } ;
entry [ 0 ] . s_name [ 0 ] = ' A ' ;
entry [ 0 ] . s_offset = 8 ;
entry [ 0 ] . s_size = 16 ;
entry [ 0 ] . s_type = vISA : : GenSymType : : S_GLOBAL_VAR ;
entry [ 1 ] . s_name [ 0 ] = ' B ' ;
entry [ 1 ] . s_offset = 24 ;
entry [ 1 ] . s_size = 8 ;
entry [ 1 ] . s_type = vISA : : GenSymType : : S_GLOBAL_VAR_CONST ;
EXPECT_EQ ( 0U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
auto decodeResult = linkerInput . decodeGlobalVariablesSymbolTable ( entry , 2 ) ;
EXPECT_TRUE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
EXPECT_EQ ( 2U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
auto symbolA = linkerInput . getSymbols ( ) . find ( " A " ) ;
ASSERT_NE ( linkerInput . getSymbols ( ) . end ( ) , symbolA ) ;
EXPECT_EQ ( entry [ 0 ] . s_offset , symbolA - > second . offset ) ;
EXPECT_EQ ( entry [ 0 ] . s_size , symbolA - > second . size ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , symbolA - > second . segment ) ;
2019-07-04 17:14:51 +02:00
auto symbolB = linkerInput . getSymbols ( ) . find ( " B " ) ;
ASSERT_NE ( linkerInput . getSymbols ( ) . end ( ) , symbolB ) ;
EXPECT_EQ ( entry [ 1 ] . s_offset , symbolB - > second . offset ) ;
EXPECT_EQ ( entry [ 1 ] . s_size , symbolB - > second . size ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , symbolB - > second . segment ) ;
2019-07-04 17:14:51 +02:00
auto symbolC = linkerInput . getSymbols ( ) . find ( " C " ) ;
EXPECT_EQ ( linkerInput . getSymbols ( ) . end ( ) , symbolC ) ;
}
TEST ( LinkerInputTests , givenFunctionsSymbolTableThenProperlyDecodesGlobalVariablesAndGlobalConstants ) {
// Note : this is subject to change in IGC shotly.
// GLOBAL_VAR/CONST will be ultimately allowed only in globalVariables symbol table.
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry entry [ 2 ] = { { } , { } } ;
entry [ 0 ] . s_name [ 0 ] = ' A ' ;
entry [ 0 ] . s_offset = 8 ;
entry [ 0 ] . s_size = 16 ;
entry [ 0 ] . s_type = vISA : : GenSymType : : S_GLOBAL_VAR ;
entry [ 1 ] . s_name [ 0 ] = ' B ' ;
entry [ 1 ] . s_offset = 24 ;
entry [ 1 ] . s_size = 8 ;
entry [ 1 ] . s_type = vISA : : GenSymType : : S_GLOBAL_VAR_CONST ;
EXPECT_EQ ( 0U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
auto decodeResult = linkerInput . decodeExportedFunctionsSymbolTable ( entry , 2 , 3 ) ;
EXPECT_TRUE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
EXPECT_EQ ( 2U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
auto symbolA = linkerInput . getSymbols ( ) . find ( " A " ) ;
ASSERT_NE ( linkerInput . getSymbols ( ) . end ( ) , symbolA ) ;
EXPECT_EQ ( entry [ 0 ] . s_offset , symbolA - > second . offset ) ;
EXPECT_EQ ( entry [ 0 ] . s_size , symbolA - > second . size ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , symbolA - > second . segment ) ;
2019-07-04 17:14:51 +02:00
auto symbolB = linkerInput . getSymbols ( ) . find ( " B " ) ;
ASSERT_NE ( linkerInput . getSymbols ( ) . end ( ) , symbolB ) ;
EXPECT_EQ ( entry [ 1 ] . s_offset , symbolB - > second . offset ) ;
EXPECT_EQ ( entry [ 1 ] . s_size , symbolB - > second . size ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , symbolB - > second . segment ) ;
2019-07-04 17:14:51 +02:00
auto symbolC = linkerInput . getSymbols ( ) . find ( " C " ) ;
EXPECT_EQ ( linkerInput . getSymbols ( ) . end ( ) , symbolC ) ;
}
TEST ( LinkerInputTests , givenGlobalsSymbolTableThenFunctionExportsAreNotAllowed ) {
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry entry = { } ;
entry . s_name [ 0 ] = ' A ' ;
entry . s_offset = 8 ;
entry . s_size = 16 ;
entry . s_type = vISA : : GenSymType : : S_FUNC ;
auto decodeResult = linkerInput . decodeGlobalVariablesSymbolTable ( & entry , 1 ) ;
EXPECT_FALSE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_FALSE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
}
TEST ( LinkerInputTests , givenFunctionsSymbolTableThenProperlyDecodesExportedFunctions ) {
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry entry [ 2 ] = { { } , { } } ;
entry [ 0 ] . s_name [ 0 ] = ' A ' ;
entry [ 0 ] . s_offset = 8 ;
entry [ 0 ] . s_size = 16 ;
entry [ 0 ] . s_type = vISA : : GenSymType : : S_FUNC ;
entry [ 1 ] . s_name [ 0 ] = ' B ' ;
entry [ 1 ] . s_offset = 24 ;
entry [ 1 ] . s_size = 8 ;
entry [ 1 ] . s_type = vISA : : GenSymType : : S_FUNC ;
EXPECT_EQ ( 0U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
EXPECT_EQ ( - 1 , linkerInput . getExportedFunctionsSegmentId ( ) ) ;
auto decodeResult = linkerInput . decodeExportedFunctionsSymbolTable ( entry , 2 , 3 ) ;
EXPECT_TRUE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
EXPECT_EQ ( 2U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
auto symbolA = linkerInput . getSymbols ( ) . find ( " A " ) ;
ASSERT_NE ( linkerInput . getSymbols ( ) . end ( ) , symbolA ) ;
EXPECT_EQ ( entry [ 0 ] . s_offset , symbolA - > second . offset ) ;
EXPECT_EQ ( entry [ 0 ] . s_size , symbolA - > second . size ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( NEO : : SegmentType : : Instructions , symbolA - > second . segment ) ;
2019-07-04 17:14:51 +02:00
auto symbolB = linkerInput . getSymbols ( ) . find ( " B " ) ;
ASSERT_NE ( linkerInput . getSymbols ( ) . end ( ) , symbolB ) ;
EXPECT_EQ ( entry [ 1 ] . s_offset , symbolB - > second . offset ) ;
EXPECT_EQ ( entry [ 1 ] . s_size , symbolB - > second . size ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( NEO : : SegmentType : : Instructions , symbolB - > second . segment ) ;
2019-07-04 17:14:51 +02:00
EXPECT_EQ ( 3 , linkerInput . getExportedFunctionsSegmentId ( ) ) ;
}
TEST ( LinkerInputTests , givenFunctionsSymbolTableThenUndefIsNotAllowed ) {
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry entry = { } ;
entry . s_name [ 0 ] = ' A ' ;
entry . s_offset = 8 ;
entry . s_size = 16 ;
entry . s_type = vISA : : GenSymType : : S_UNDEF ;
auto decodeResult = linkerInput . decodeExportedFunctionsSymbolTable ( & entry , 1 , 3 ) ;
EXPECT_FALSE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_FALSE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
}
TEST ( LinkerInputTests , givenRelocationTableThenRelocationEntriesAreProperlyParsed ) {
NEO : : LinkerInput linkerInput ;
vISA : : GenRelocEntry entry = { } ;
entry . r_symbol [ 0 ] = ' A ' ;
entry . r_offset = 8 ;
entry . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
auto decodeResult = linkerInput . decodeRelocationTable ( & entry , 1 , 3 ) ;
EXPECT_TRUE ( decodeResult ) ;
EXPECT_EQ ( 0U , linkerInput . getSymbols ( ) . size ( ) ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
decodeResult = linkerInput . decodeRelocationTable ( & entry , 1 , 1 ) ;
EXPECT_TRUE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerInputTests , givenRelocationTableThenNoneAsRelocationTypeIsNotAllowed ) {
2019-07-04 17:14:51 +02:00
NEO : : LinkerInput linkerInput ;
vISA : : GenRelocEntry entry = { } ;
entry . r_symbol [ 0 ] = ' A ' ;
entry . r_offset = 8 ;
entry . r_type = vISA : : GenRelocType : : R_NONE ;
auto decodeResult = linkerInput . decodeRelocationTable ( & entry , 1 , 3 ) ;
EXPECT_FALSE ( decodeResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_FALSE ( linkerInput . isValid ( ) ) ;
}
TEST ( LinkerInputTests , whenDataRelocationsAreAddedThenProperTraitsAreSet ) {
NEO : : LinkerInput linkerInput ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalConstantsBuffer ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalVariablesBuffer ) ;
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 7U ;
relocInfo . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocInfo . symbolName = " aaa " ;
relocInfo . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
linkerInput . addDataRelocationInfo ( relocInfo ) ;
ASSERT_EQ ( 1U , linkerInput . getDataRelocations ( ) . size ( ) ) ;
EXPECT_EQ ( relocInfo . offset , linkerInput . getDataRelocations ( ) [ 0 ] . offset ) ;
EXPECT_EQ ( relocInfo . relocationSegment , linkerInput . getDataRelocations ( ) [ 0 ] . relocationSegment ) ;
EXPECT_EQ ( relocInfo . symbolName , linkerInput . getDataRelocations ( ) [ 0 ] . symbolName ) ;
EXPECT_EQ ( relocInfo . symbolSegment , linkerInput . getDataRelocations ( ) [ 0 ] . symbolSegment ) ;
EXPECT_EQ ( relocInfo . type , linkerInput . getDataRelocations ( ) [ 0 ] . type ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalConstantsBuffer ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalVariablesBuffer ) ;
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
linkerInput = { } ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalConstantsBuffer ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalVariablesBuffer ) ;
relocInfo . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocInfo . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
linkerInput . addDataRelocationInfo ( relocInfo ) ;
ASSERT_EQ ( 1U , linkerInput . getDataRelocations ( ) . size ( ) ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalConstantsBuffer ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalVariablesBuffer ) ;
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
2019-07-04 17:14:51 +02:00
}
2021-01-19 17:29:20 +01:00
TEST ( LinkerInputTests , WhenGettingSegmentForSectionNameThenCorrectSegmentIsReturned ) {
auto segmentConst = NEO : : LinkerInput : : getSegmentForSection ( NEO : : Elf : : SectionsNamesZebin : : dataConst . str ( ) ) ;
auto segmentGlobalConst = NEO : : LinkerInput : : getSegmentForSection ( NEO : : Elf : : SectionsNamesZebin : : dataGlobalConst . str ( ) ) ;
auto segmentGlobal = NEO : : LinkerInput : : getSegmentForSection ( NEO : : Elf : : SectionsNamesZebin : : dataGlobal . str ( ) ) ;
auto segmentInstructions = NEO : : LinkerInput : : getSegmentForSection ( NEO : : Elf : : SectionsNamesZebin : : textPrefix . str ( ) ) ;
auto segmentInstructions2 = NEO : : LinkerInput : : getSegmentForSection ( " .text.abc " ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , segmentConst ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , segmentGlobalConst ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , segmentGlobal ) ;
EXPECT_EQ ( NEO : : SegmentType : : Instructions , segmentInstructions ) ;
EXPECT_EQ ( NEO : : SegmentType : : Instructions , segmentInstructions2 ) ;
}
TEST ( LinkerInputTests , WhenGettingSegmentForUnknownSectionNameThenUnknownSegmentIsReturned ) {
auto segment = NEO : : LinkerInput : : getSegmentForSection ( " Not_a_valid_section_name " ) ;
EXPECT_EQ ( NEO : : SegmentType : : Unknown , segment ) ;
}
TEST ( LinkerInputTests , WhenAddingElfTextRelocationForSegmentIndexThenInstructionSegmentForRelocationAndProperTraitsAreSet ) {
NEO : : LinkerInput linkerInput = { } ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalConstantsBuffer ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalVariablesBuffer ) ;
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 7u ;
relocInfo . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocInfo . symbolName = " test " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
relocInfo . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocInfo . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
linkerInput . addElfTextSegmentRelocation ( relocInfo , 5 ) ;
ASSERT_EQ ( 0u , linkerInput . getDataRelocations ( ) . size ( ) ) ;
ASSERT_EQ ( 6u , linkerInput . getRelocationsInInstructionSegments ( ) . size ( ) ) ;
auto relocs = linkerInput . getRelocationsInInstructionSegments ( ) [ 5 ] ;
ASSERT_EQ ( 1u , relocs . size ( ) ) ;
EXPECT_EQ ( NEO : : SegmentType : : Instructions , relocs [ 0 ] . relocationSegment ) ;
EXPECT_EQ ( NEO : : SegmentType : : Unknown , relocs [ 0 ] . symbolSegment ) ;
EXPECT_EQ ( std : : string ( " test " ) , relocs [ 0 ] . symbolName ) ;
EXPECT_EQ ( 7u , relocs [ 0 ] . offset ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalConstantsBuffer ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . requiresPatchingOfGlobalVariablesBuffer ) ;
EXPECT_TRUE ( linkerInput . isValid ( ) ) ;
}
TEST ( LinkerInputTests , WhenAddingTwoElfTextRelocationForSingleSegmentIndexThenBothRelocationsAreAddedForTheSameSegment ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 7u ;
relocInfo . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocInfo . symbolName = " test " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
relocInfo . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocInfo . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
linkerInput . addElfTextSegmentRelocation ( relocInfo , 0 ) ;
ASSERT_EQ ( 1u , linkerInput . getRelocationsInInstructionSegments ( ) . size ( ) ) ;
auto & relocs = linkerInput . getRelocationsInInstructionSegments ( ) [ 0 ] ;
EXPECT_EQ ( 1u , relocs . size ( ) ) ;
relocInfo . offset = 24u ;
linkerInput . addElfTextSegmentRelocation ( relocInfo , 0 ) ;
EXPECT_EQ ( 2u , relocs . size ( ) ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . requiresPatchingOfInstructionSegments ) ;
}
TEST ( LinkerInputTests , WhenDecodingElfTextRelocationsThenCorrectRelocationsAreAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.const " ;
sectionNames [ 2 ] = " .text.hello " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 0 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc2 ;
reloc2 . offset = 32 ;
reloc2 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_32 ) ;
reloc2 . symbolName = " symbol2 " ;
reloc2 . symbolSectionIndex = 1 ;
reloc2 . symbolTableIndex = 0 ;
reloc2 . targetSectionIndex = 2 ;
elf64 . relocations . emplace_back ( reloc2 ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
nameToKernelId [ " hello " ] = 1 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getRelocationsInInstructionSegments ( ) ;
ASSERT_EQ ( 2u , relocations . size ( ) ) ;
auto & segment0Relocs = relocations [ 0 ] ;
ASSERT_EQ ( 1u , segment0Relocs . size ( ) ) ;
EXPECT_EQ ( 64u , segment0Relocs [ 0 ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : Instructions , segment0Relocs [ 0 ] . relocationSegment ) ;
EXPECT_EQ ( " symbol1 " , segment0Relocs [ 0 ] . symbolName ) ;
EXPECT_EQ ( NEO : : SegmentType : : Unknown , segment0Relocs [ 0 ] . symbolSegment ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : Address , segment0Relocs [ 0 ] . type ) ;
auto & segment1Relocs = relocations [ 1 ] ;
ASSERT_EQ ( 1u , segment1Relocs . size ( ) ) ;
EXPECT_EQ ( 32u , segment1Relocs [ 0 ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : Instructions , segment1Relocs [ 0 ] . relocationSegment ) ;
EXPECT_EQ ( " symbol2 " , segment1Relocs [ 0 ] . symbolName ) ;
EXPECT_EQ ( NEO : : SegmentType : : Unknown , segment1Relocs [ 0 ] . symbolSegment ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : AddressLow , segment1Relocs [ 0 ] . type ) ;
}
TEST ( LinkerInputTests , GivenNoKernelNameToIdWhenDecodingElfTextRelocationsThenNoRelocationIsAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.const " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 0 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " wrong_name " ] = 0 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getRelocationsInInstructionSegments ( ) ;
ASSERT_EQ ( 0u , relocations . size ( ) ) ;
}
TEST ( LinkerInputTests , GivenInvalidTextSectionNameWhenDecodingElfTextRelocationsThenNoRelocationIsAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .invalid.abc " ;
sectionNames [ 1 ] = " .data.const " ;
sectionNames [ 2 ] = " .text.hello " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 0 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
nameToKernelId [ " hello " ] = 1 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getRelocationsInInstructionSegments ( ) ;
ASSERT_EQ ( 0u , relocations . size ( ) ) ;
}
TEST ( LinkerInputTests , GivenInvalidRelocationTypeWhenDecodingElfTextRelocationsThenUnknownTypeIsSet ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.const " ;
sectionNames [ 2 ] = " .text.hello " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = 0xffffffff ; // invalid type
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 0 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
nameToKernelId [ " hello " ] = 1 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getRelocationsInInstructionSegments ( ) ;
ASSERT_EQ ( 1u , relocations . size ( ) ) ;
ASSERT_EQ ( 1u , relocations [ 0 ] . size ( ) ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : Unknown , relocations [ 0 ] [ 0 ] . type ) ;
}
TEST ( LinkerInputTests , WhenDecodingElfGlobalDataRelocationsThenCorrectRelocationsAreAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.global " ;
sectionNames [ 2 ] = " .data.const " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 1 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc2 ;
reloc2 . offset = 32 ;
reloc2 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc2 . symbolName = " symbol2 " ;
reloc2 . symbolSectionIndex = 2 ;
reloc2 . symbolTableIndex = 0 ;
reloc2 . targetSectionIndex = 1 ;
elf64 . relocations . emplace_back ( reloc2 ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getDataRelocations ( ) ;
ASSERT_EQ ( 2u , relocations . size ( ) ) ;
EXPECT_EQ ( 64u , relocations [ 0 ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , relocations [ 0 ] . relocationSegment ) ;
EXPECT_EQ ( " symbol1 " , relocations [ 0 ] . symbolName ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , relocations [ 0 ] . symbolSegment ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : Address , relocations [ 0 ] . type ) ;
EXPECT_EQ ( 32u , relocations [ 1 ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , relocations [ 1 ] . relocationSegment ) ;
EXPECT_EQ ( " symbol2 " , relocations [ 1 ] . symbolName ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , relocations [ 1 ] . symbolSegment ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : Address , relocations [ 1 ] . type ) ;
}
TEST ( LinkerInputTests , WhenDecodingElfConstantDataRelocationsThenCorrectRelocationsAreAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.global " ;
sectionNames [ 2 ] = " .data.const " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 2 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc2 ;
reloc2 . offset = 32 ;
reloc2 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc2 . symbolName = " symbol2 " ;
reloc2 . symbolSectionIndex = 2 ;
reloc2 . symbolTableIndex = 0 ;
reloc2 . targetSectionIndex = 2 ;
elf64 . relocations . emplace_back ( reloc2 ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getDataRelocations ( ) ;
ASSERT_EQ ( 2u , relocations . size ( ) ) ;
EXPECT_EQ ( 64u , relocations [ 0 ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , relocations [ 0 ] . relocationSegment ) ;
EXPECT_EQ ( " symbol1 " , relocations [ 0 ] . symbolName ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalVariables , relocations [ 0 ] . symbolSegment ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : Address , relocations [ 0 ] . type ) ;
EXPECT_EQ ( 32u , relocations [ 1 ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , relocations [ 1 ] . relocationSegment ) ;
EXPECT_EQ ( " symbol2 " , relocations [ 1 ] . symbolName ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , relocations [ 1 ] . symbolSegment ) ;
EXPECT_EQ ( NEO : : LinkerInput : : RelocationInfo : : Type : : Address , relocations [ 1 ] . type ) ;
}
TEST ( LinkerInputTests , GivenUnsupportedDataSegmentWhenDecodingElfDataRelocationThenNoRelocationsAreAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data " ;
sectionNames [ 2 ] = " .data.const " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 2 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 1 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getDataRelocations ( ) ;
ASSERT_EQ ( 0u , relocations . size ( ) ) ;
}
TEST ( LinkerInputTests , GivenUnsupportedSymbolSegmentWhenDecodingElfDataRelocationThenNoRelocationsAreAddedAndDebugBreakIsCalled ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data " ;
sectionNames [ 2 ] = " .data.const " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc ;
reloc . offset = 64 ;
reloc . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc . symbolName = " symbol1 " ;
reloc . symbolSectionIndex = 1 ;
reloc . symbolTableIndex = 0 ;
reloc . targetSectionIndex = 2 ;
elf64 . relocations . emplace_back ( reloc ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto relocations = linkerInput . getDataRelocations ( ) ;
ASSERT_EQ ( 0u , relocations . size ( ) ) ;
}
TEST ( LinkerInputTests , GivenGlobalAndLocalElfSymbolsWhenDecodingThenOnlyGlobalSymbolsAreAdded ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.const " ;
sectionNames [ 2 ] = " .text.hello " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
elf64 . overrideSymbolName = true ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol ;
symbol . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_OBJECT | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_GLOBAL < < 4 ;
symbol . name = 0 ;
symbol . other = 0 ;
symbol . shndx = 1 ;
symbol . size = 8 ;
symbol . value = 0x1234000 ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol2 ;
symbol2 . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_FUNC | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_GLOBAL < < 4 ;
symbol2 . name = 8 ;
symbol2 . other = 0 ;
symbol2 . shndx = 0 ;
symbol2 . size = 16 ;
symbol2 . value = 0x5000 ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol3 ;
symbol3 . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_FUNC | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_LOCAL < < 4 ;
symbol3 . name = 16 ;
symbol3 . other = 0 ;
symbol3 . shndx = 0 ;
symbol3 . size = 8 ;
symbol3 . value = 0 ;
elf64 . symbolTable . emplace_back ( symbol ) ;
elf64 . symbolTable . emplace_back ( symbol2 ) ;
elf64 . symbolTable . emplace_back ( symbol3 ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
nameToKernelId [ " hello " ] = 1 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto symbols = linkerInput . getSymbols ( ) ;
ASSERT_EQ ( 2u , symbols . size ( ) ) ;
EXPECT_EQ ( 0x1234000u , symbols [ std : : to_string ( symbol . name ) ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : GlobalConstants , symbols [ std : : to_string ( symbol . name ) ] . segment ) ;
EXPECT_EQ ( 8u , symbols [ std : : to_string ( symbol . name ) ] . size ) ;
EXPECT_EQ ( 0x5000u , symbols [ std : : to_string ( symbol2 . name ) ] . offset ) ;
EXPECT_EQ ( NEO : : SegmentType : : Instructions , symbols [ std : : to_string ( symbol2 . name ) ] . segment ) ;
EXPECT_EQ ( 16u , symbols [ std : : to_string ( symbol2 . name ) ] . size ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_TRUE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
}
TEST ( LinkerInputTests , GivenGlobalFunctionsInTwoSegementsWhenDecodingThenUnrecoverableIsCalled ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.const " ;
sectionNames [ 2 ] = " .text.hello " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
elf64 . overrideSymbolName = true ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol ;
symbol . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_FUNC | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_GLOBAL < < 4 ;
symbol . name = 0 ;
symbol . other = 0 ;
symbol . shndx = 0 ;
symbol . size = 8 ;
symbol . value = 0x1234000 ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol2 ;
symbol2 . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_FUNC | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_GLOBAL < < 4 ;
symbol2 . name = 8 ;
symbol2 . other = 0 ;
symbol2 . shndx = 2 ;
symbol2 . size = 16 ;
symbol2 . value = 0x5000 ;
elf64 . symbolTable . emplace_back ( symbol ) ;
elf64 . symbolTable . emplace_back ( symbol2 ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
nameToKernelId [ " hello " ] = 1 ;
EXPECT_THROW ( linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) , std : : exception ) ;
auto symbols = linkerInput . getSymbols ( ) ;
ASSERT_EQ ( 2u , symbols . size ( ) ) ;
EXPECT_EQ ( 0 , linkerInput . getExportedFunctionsSegmentId ( ) ) ;
}
TEST ( LinkerInputTests , GivenNoKernelNameToIdWhenDecodingGlobalFunctionThenExportedFunctionsSegmentIsNotSet ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
elf64 . overrideSymbolName = true ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol ;
symbol . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_FUNC | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_GLOBAL < < 4 ;
symbol . name = 0 ;
symbol . other = 0 ;
symbol . shndx = 0 ;
symbol . size = 8 ;
symbol . value = 0x1234000 ;
elf64 . symbolTable . emplace_back ( symbol ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " hello " ] = 1 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto symbols = linkerInput . getSymbols ( ) ;
ASSERT_EQ ( 1u , symbols . size ( ) ) ;
EXPECT_EQ ( - 1 , linkerInput . getExportedFunctionsSegmentId ( ) ) ;
}
TEST ( LinkerInputTests , GivenGlobalElfSymbolOfNoTypeWhenDecodingThenSymbolWithUnknownSegmentIsAddedAndDebugBreakCalled ) {
NEO : : LinkerInput linkerInput = { } ;
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text.abc " ;
sectionNames [ 1 ] = " .data.const " ;
sectionNames [ 2 ] = " .text.hello " ;
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
elf64 . overrideSymbolName = true ;
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol ;
symbol . info = NEO : : Elf : : SYMBOL_TABLE_TYPE : : STT_NOTYPE | NEO : : Elf : : SYMBOL_TABLE_BIND : : STB_GLOBAL < < 4 ;
symbol . name = 0 ;
symbol . other = 0 ;
symbol . shndx = 1 ;
symbol . size = 8 ;
symbol . value = 0x1234000 ;
elf64 . symbolTable . emplace_back ( symbol ) ;
NEO : : LinkerInput : : SectionNameToSegmentIdMap nameToKernelId ;
nameToKernelId [ " abc " ] = 0 ;
nameToKernelId [ " hello " ] = 1 ;
linkerInput . decodeElfSymbolTableAndRelocations ( elf64 , nameToKernelId ) ;
auto symbols = linkerInput . getSymbols ( ) ;
ASSERT_EQ ( 1u , symbols . size ( ) ) ;
EXPECT_EQ ( SegmentType : : Unknown , symbols . begin ( ) - > second . segment ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalVariables ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsGlobalConstants ) ;
EXPECT_FALSE ( linkerInput . getTraits ( ) . exportsFunctions ) ;
}
2019-07-04 17:14:51 +02:00
TEST ( LinkerTests , givenEmptyLinkerInputThenLinkerOutputIsEmpty ) {
NEO : : LinkerInput linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : SegmentInfo globalVar , globalConst , exportedFunc ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2019-07-04 17:14:51 +02:00
NEO : : Linker : : PatchableSegments patchableInstructionSegments ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVar , globalConst , exportedFunc ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2019-07-04 17:14:51 +02:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
auto relocatedSymbols = linker . extractRelocatedSymbols ( ) ;
EXPECT_EQ ( 0U , relocatedSymbols . size ( ) ) ;
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerTests , givenInvalidLinkerInputThenLinkerFails ) {
WhiteBox < NEO : : LinkerInput > mockLinkerInput ;
mockLinkerInput . valid = false ;
NEO : : Linker linker ( mockLinkerInput ) ;
NEO : : Linker : : SegmentInfo globalVar , globalConst , exportedFunc ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : PatchableSegments patchableInstructionSegments ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVar , globalConst , exportedFunc ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : Error , linkResult ) ;
2020-01-11 18:25:26 +01:00
}
2020-07-13 18:42:11 +02:00
TEST ( LinkerTests , givenUnresolvedExternalWhenPatchingInstructionsThenLinkPartially ) {
2019-07-04 17:14:51 +02:00
NEO : : LinkerInput linkerInput ;
vISA : : GenRelocEntry entry = { } ;
entry . r_symbol [ 0 ] = ' A ' ;
entry . r_offset = 8 ;
entry . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
auto decodeResult = linkerInput . decodeRelocationTable ( & entry , 1 , 0 ) ;
EXPECT_TRUE ( decodeResult ) ;
NEO : : Linker linker ( linkerInput ) ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : SegmentInfo globalVar , globalConst , exportedFunc ;
2019-07-04 17:14:51 +02:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > instructionSegment ;
instructionSegment . resize ( 64 ) ;
NEO : : Linker : : PatchableSegment seg0 ;
seg0 . hostPointer = instructionSegment . data ( ) ;
seg0 . segmentSize = instructionSegment . size ( ) ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2019-07-04 17:14:51 +02:00
NEO : : Linker : : PatchableSegments patchableInstructionSegments { seg0 } ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVar , globalConst , exportedFunc ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2019-07-04 17:14:51 +02:00
auto relocatedSymbols = linker . extractRelocatedSymbols ( ) ;
EXPECT_EQ ( 0U , relocatedSymbols . size ( ) ) ;
ASSERT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
EXPECT_EQ ( 0U , unresolvedExternals [ 0 ] . instructionsSegmentId ) ;
EXPECT_FALSE ( unresolvedExternals [ 0 ] . internalError ) ;
EXPECT_EQ ( entry . r_offset , unresolvedExternals [ 0 ] . unresolvedRelocation . offset ) ;
EXPECT_EQ ( std : : string ( entry . r_symbol ) , std : : string ( unresolvedExternals [ 0 ] . unresolvedRelocation . symbolName ) ) ;
}
TEST ( LinkerTests , givenValidSymbolsAndRelocationsThenInstructionSegmentsAreProperlyPatched ) {
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry symGlobalVariable = { } ;
symGlobalVariable . s_name [ 0 ] = ' A ' ;
symGlobalVariable . s_offset = 4 ;
symGlobalVariable . s_size = 16 ;
symGlobalVariable . s_type = vISA : : GenSymType : : S_GLOBAL_VAR ;
bool decodeSymSuccess = linkerInput . decodeGlobalVariablesSymbolTable ( & symGlobalVariable , 1 ) ;
vISA : : GenSymEntry symGlobalConstant = { } ;
symGlobalConstant . s_name [ 0 ] = ' B ' ;
symGlobalConstant . s_offset = 20 ;
symGlobalConstant . s_size = 8 ;
symGlobalConstant . s_type = vISA : : GenSymType : : S_GLOBAL_VAR_CONST ;
decodeSymSuccess = decodeSymSuccess & & linkerInput . decodeGlobalVariablesSymbolTable ( & symGlobalConstant , 1 ) ;
vISA : : GenSymEntry symExportedFunc = { } ;
symExportedFunc . s_name [ 0 ] = ' C ' ;
symExportedFunc . s_offset = 16 ;
symExportedFunc . s_size = 32 ;
symExportedFunc . s_type = vISA : : GenSymType : : S_FUNC ;
decodeSymSuccess = decodeSymSuccess & & linkerInput . decodeExportedFunctionsSymbolTable ( & symExportedFunc , 1 , 0 ) ;
EXPECT_TRUE ( decodeSymSuccess ) ;
vISA : : GenRelocEntry relocA = { } ;
relocA . r_symbol [ 0 ] = ' A ' ;
relocA . r_offset = 0 ;
relocA . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
vISA : : GenRelocEntry relocB = { } ;
relocB . r_symbol [ 0 ] = ' B ' ;
relocB . r_offset = 8 ;
relocB . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
vISA : : GenRelocEntry relocC = { } ;
relocC . r_symbol [ 0 ] = ' C ' ;
relocC . r_offset = 16 ;
relocC . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
2019-11-25 22:43:21 +01:00
vISA : : GenRelocEntry relocCPartHigh = { } ;
relocCPartHigh . r_symbol [ 0 ] = ' C ' ;
relocCPartHigh . r_offset = 28 ;
relocCPartHigh . r_type = vISA : : GenRelocType : : R_SYM_ADDR_32_HI ;
vISA : : GenRelocEntry relocCPartLow = { } ;
relocCPartLow . r_symbol [ 0 ] = ' C ' ;
relocCPartLow . r_offset = 36 ;
relocCPartLow . r_type = vISA : : GenRelocType : : R_SYM_ADDR_32 ;
2020-09-07 02:28:32 +02:00
vISA : : GenRelocEntry relocIgnore = { } ;
relocIgnore . r_symbol [ 0 ] = ' X ' ;
relocIgnore . r_offset = 36 ;
relocIgnore . r_type = vISA : : GenRelocType : : R_PER_THREAD_PAYLOAD_OFFSET_32 ;
vISA : : GenRelocEntry relocs [ ] = { relocA , relocB , relocC , relocCPartHigh , relocCPartLow , relocIgnore } ;
constexpr uint32_t numRelocations = sizeof ( relocs ) / sizeof ( relocs [ 0 ] ) ;
bool decodeRelocSuccess = linkerInput . decodeRelocationTable ( & relocs , numRelocations , 0 ) ;
2019-07-04 17:14:51 +02:00
EXPECT_TRUE ( decodeRelocSuccess ) ;
NEO : : Linker linker ( linkerInput ) ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : SegmentInfo globalVarSegment , globalConstSegment , exportedFuncSegment ;
2019-07-04 17:14:51 +02:00
globalVarSegment . gpuAddress = 8 ;
globalVarSegment . segmentSize = 64 ;
globalConstSegment . gpuAddress = 128 ;
globalConstSegment . segmentSize = 256 ;
exportedFuncSegment . gpuAddress = 4096 ;
exportedFuncSegment . segmentSize = 1024 ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > instructionSegment ;
2019-11-25 22:43:21 +01:00
uint32_t initData = 0x77777777 ;
instructionSegment . resize ( 64 , static_cast < char > ( initData ) ) ;
2019-07-04 17:14:51 +02:00
NEO : : Linker : : PatchableSegment seg0 ;
seg0 . hostPointer = instructionSegment . data ( ) ;
seg0 . segmentSize = instructionSegment . size ( ) ;
NEO : : Linker : : PatchableSegments patchableInstructionSegments { seg0 } ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2019-07-04 17:14:51 +02:00
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-07-14 16:44:28 +02:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments , unresolvedExternals ,
nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2019-07-04 17:14:51 +02:00
auto relocatedSymbols = linker . extractRelocatedSymbols ( ) ;
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
EXPECT_EQ ( 3U , relocatedSymbols . size ( ) ) ;
ASSERT_EQ ( 1U , relocatedSymbols . count ( symGlobalVariable . s_name ) ) ;
ASSERT_EQ ( 1U , relocatedSymbols . count ( symGlobalConstant . s_name ) ) ;
ASSERT_EQ ( 1U , relocatedSymbols . count ( symGlobalVariable . s_name ) ) ;
EXPECT_EQ ( relocatedSymbols [ symGlobalVariable . s_name ] . gpuAddress , globalVarSegment . gpuAddress + symGlobalVariable . s_offset ) ;
EXPECT_EQ ( relocatedSymbols [ symGlobalConstant . s_name ] . gpuAddress , globalConstSegment . gpuAddress + symGlobalConstant . s_offset ) ;
EXPECT_EQ ( relocatedSymbols [ symExportedFunc . s_name ] . gpuAddress , exportedFuncSegment . gpuAddress + symExportedFunc . s_offset ) ;
EXPECT_EQ ( relocatedSymbols [ symGlobalVariable . s_name ] . gpuAddress , * reinterpret_cast < const uintptr_t * > ( instructionSegment . data ( ) + relocA . r_offset ) ) ;
EXPECT_EQ ( relocatedSymbols [ symGlobalConstant . s_name ] . gpuAddress , * reinterpret_cast < const uintptr_t * > ( instructionSegment . data ( ) + relocB . r_offset ) ) ;
EXPECT_EQ ( relocatedSymbols [ symExportedFunc . s_name ] . gpuAddress , * reinterpret_cast < const uintptr_t * > ( instructionSegment . data ( ) + relocC . r_offset ) ) ;
2019-11-25 22:43:21 +01:00
auto funcGpuAddressAs64bit = static_cast < uint64_t > ( relocatedSymbols [ symExportedFunc . s_name ] . gpuAddress ) ;
auto funcAddressLow = static_cast < uint32_t > ( funcGpuAddressAs64bit & 0xffffffff ) ;
auto funcAddressHigh = static_cast < uint32_t > ( ( funcGpuAddressAs64bit > > 32 ) & 0xffffffff ) ;
EXPECT_EQ ( funcAddressLow , * reinterpret_cast < const uint32_t * > ( instructionSegment . data ( ) + relocCPartLow . r_offset ) ) ;
EXPECT_EQ ( initData , * reinterpret_cast < const uint32_t * > ( instructionSegment . data ( ) + relocCPartLow . r_offset - sizeof ( uint32_t ) ) ) ;
EXPECT_EQ ( initData , * reinterpret_cast < const uint32_t * > ( instructionSegment . data ( ) + relocCPartLow . r_offset + sizeof ( uint32_t ) ) ) ;
EXPECT_EQ ( funcAddressHigh , * reinterpret_cast < const uint32_t * > ( instructionSegment . data ( ) + relocCPartHigh . r_offset ) ) ;
EXPECT_EQ ( initData , * reinterpret_cast < const uint32_t * > ( instructionSegment . data ( ) + relocCPartHigh . r_offset - sizeof ( uint32_t ) ) ) ;
EXPECT_EQ ( initData , * reinterpret_cast < const uint32_t * > ( instructionSegment . data ( ) + relocCPartHigh . r_offset + sizeof ( uint32_t ) ) ) ;
2019-07-04 17:14:51 +02:00
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerTests , givenInvalidSymbolOffsetWhenPatchingInstructionsThenRelocationFails ) {
2019-07-04 17:14:51 +02:00
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry symGlobalVariable = { } ;
symGlobalVariable . s_name [ 0 ] = ' A ' ;
symGlobalVariable . s_offset = 64 ;
symGlobalVariable . s_size = 16 ;
symGlobalVariable . s_type = vISA : : GenSymType : : S_GLOBAL_VAR ;
bool decodeSymSuccess = linkerInput . decodeGlobalVariablesSymbolTable ( & symGlobalVariable , 1 ) ;
EXPECT_TRUE ( decodeSymSuccess ) ;
NEO : : Linker linker ( linkerInput ) ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : SegmentInfo globalVarSegment , globalConstSegment , exportedFuncSegment ;
2019-07-04 17:14:51 +02:00
globalVarSegment . gpuAddress = 8 ;
globalVarSegment . segmentSize = symGlobalVariable . s_offset ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > instructionSegment ;
instructionSegment . resize ( 64 , 0 ) ;
NEO : : Linker : : PatchableSegment seg0 ;
seg0 . hostPointer = instructionSegment . data ( ) ;
seg0 . segmentSize = instructionSegment . size ( ) ;
NEO : : Linker : : PatchableSegments patchableInstructionSegments { seg0 } ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2019-07-04 17:14:51 +02:00
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : Error , linkResult ) ;
2019-07-04 17:14:51 +02:00
auto relocatedSymbols = linker . extractRelocatedSymbols ( ) ;
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
EXPECT_EQ ( 0U , relocatedSymbols . size ( ) ) ;
globalVarSegment . segmentSize = symGlobalVariable . s_offset + symGlobalVariable . s_size ;
linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-07-14 16:44:28 +02:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments , unresolvedExternals ,
nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2019-07-04 17:14:51 +02:00
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerTests , givenInvalidRelocationOffsetThenPatchingOfInstructionsFails ) {
2019-07-04 17:14:51 +02:00
NEO : : LinkerInput linkerInput ;
vISA : : GenSymEntry symGlobalVariable = { } ;
symGlobalVariable . s_name [ 0 ] = ' A ' ;
symGlobalVariable . s_offset = 64 ;
symGlobalVariable . s_size = 16 ;
symGlobalVariable . s_type = vISA : : GenSymType : : S_GLOBAL_VAR ;
bool decodeSymSuccess = linkerInput . decodeGlobalVariablesSymbolTable ( & symGlobalVariable , 1 ) ;
EXPECT_TRUE ( decodeSymSuccess ) ;
vISA : : GenRelocEntry relocA = { } ;
relocA . r_symbol [ 0 ] = ' A ' ;
relocA . r_offset = 32 ;
relocA . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
bool decodeRelocSuccess = linkerInput . decodeRelocationTable ( & relocA , 1 , 0 ) ;
EXPECT_TRUE ( decodeRelocSuccess ) ;
NEO : : Linker linker ( linkerInput ) ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : SegmentInfo globalVarSegment , globalConstSegment , exportedFuncSegment ;
2019-07-04 17:14:51 +02:00
globalVarSegment . gpuAddress = 8 ;
globalVarSegment . segmentSize = symGlobalVariable . s_offset + symGlobalVariable . s_size ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > instructionSegment ;
instructionSegment . resize ( relocA . r_offset + sizeof ( uintptr_t ) , 0 ) ;
NEO : : Linker : : PatchableSegment seg0 ;
seg0 . hostPointer = instructionSegment . data ( ) ;
seg0 . segmentSize = relocA . r_offset ;
NEO : : Linker : : PatchableSegments patchableInstructionSegments { seg0 } ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2019-07-04 17:14:51 +02:00
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2019-07-04 17:14:51 +02:00
auto relocatedSymbols = linker . extractRelocatedSymbols ( ) ;
EXPECT_EQ ( 1U , relocatedSymbols . size ( ) ) ;
ASSERT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
EXPECT_TRUE ( unresolvedExternals [ 0 ] . internalError ) ;
patchableInstructionSegments [ 0 ] . segmentSize = relocA . r_offset + sizeof ( uintptr_t ) ;
linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2019-07-04 17:14:51 +02:00
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerTests , givenUnknownSymbolTypeWhenPatchingInstructionsThenRelocationFails ) {
2019-07-04 17:14:51 +02:00
WhiteBox < NEO : : LinkerInput > linkerInput ;
vISA : : GenSymEntry symGlobalVariable = { } ;
symGlobalVariable . s_name [ 0 ] = ' A ' ;
symGlobalVariable . s_offset = 0 ;
symGlobalVariable . s_size = 16 ;
symGlobalVariable . s_type = vISA : : GenSymType : : S_GLOBAL_VAR ;
bool decodeSymSuccess = linkerInput . decodeGlobalVariablesSymbolTable ( & symGlobalVariable , 1 ) ;
EXPECT_TRUE ( decodeSymSuccess ) ;
vISA : : GenRelocEntry relocA = { } ;
relocA . r_symbol [ 0 ] = ' A ' ;
relocA . r_offset = 0 ;
relocA . r_type = vISA : : GenRelocType : : R_SYM_ADDR ;
bool decodeRelocSuccess = linkerInput . decodeRelocationTable ( & relocA , 1 , 0 ) ;
EXPECT_TRUE ( decodeRelocSuccess ) ;
NEO : : Linker linker ( linkerInput ) ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : SegmentInfo globalVarSegment , globalConstSegment , exportedFuncSegment ;
2019-07-04 17:14:51 +02:00
globalVarSegment . gpuAddress = 8 ;
globalVarSegment . segmentSize = 64 ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > instructionSegment ;
instructionSegment . resize ( 64 , 0 ) ;
NEO : : Linker : : PatchableSegment seg0 ;
seg0 . hostPointer = instructionSegment . data ( ) ;
seg0 . segmentSize = instructionSegment . size ( ) ;
NEO : : Linker : : PatchableSegments patchableInstructionSegments { seg0 } ;
2020-07-14 16:44:28 +02:00
NEO : : GraphicsAllocation * patchableGlobalVarSeg = nullptr ;
NEO : : GraphicsAllocation * patchableConstVarSeg = nullptr ;
2019-07-04 17:14:51 +02:00
ASSERT_EQ ( 1U , linkerInput . symbols . count ( " A " ) ) ;
2020-01-11 18:25:26 +01:00
linkerInput . symbols [ " A " ] . segment = NEO : : SegmentType : : Unknown ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : Error , linkResult ) ;
2019-07-04 17:14:51 +02:00
auto relocatedSymbols = linker . extractRelocatedSymbols ( ) ;
EXPECT_EQ ( 0U , relocatedSymbols . size ( ) ) ;
ASSERT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
2020-01-11 18:25:26 +01:00
linkerInput . symbols [ " A " ] . segment = NEO : : SegmentType : : GlobalVariables ;
2019-07-04 17:14:51 +02:00
linkResult = linker . link ( globalVarSegment , globalConstSegment , exportedFuncSegment ,
2020-01-11 18:25:26 +01:00
patchableGlobalVarSeg , patchableConstVarSeg , patchableInstructionSegments ,
2020-07-14 16:44:28 +02:00
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
}
TEST ( LinkerTests , givenInvalidSourceSegmentWhenPatchingDataSegmentsThenLinkerFails ) {
WhiteBox < NEO : : LinkerInput > linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
NEO : : Linker : : SegmentInfo emptySegmentInfo ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation emptyPatchableSegment ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > nonEmptypatchableSegmentData ;
nonEmptypatchableSegmentData . resize ( 64 , 8U ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation nonEmptypatchableSegment { nonEmptypatchableSegmentData . data ( ) , nonEmptypatchableSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 0U ;
relocInfo . symbolName = " aaa " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
linkerInput . dataRelocations . push_back ( relocInfo ) ;
{
linkerInput . traits . requiresPatchingOfGlobalVariablesBuffer = true ;
linkerInput . traits . requiresPatchingOfGlobalConstantsBuffer = false ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : Unknown ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
unresolvedExternals . clear ( ) ;
linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
}
{
linkerInput . traits . requiresPatchingOfGlobalVariablesBuffer = false ;
linkerInput . traits . requiresPatchingOfGlobalConstantsBuffer = true ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : Unknown ;
unresolvedExternals . clear ( ) ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& emptyPatchableSegment , & nonEmptypatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
unresolvedExternals . clear ( ) ;
linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& emptyPatchableSegment , & nonEmptypatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
}
}
TEST ( LinkerTests , givenUnknownRelocationSegmentWhenPatchingDataSegmentsThenLinkerFails ) {
WhiteBox < NEO : : LinkerInput > linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
NEO : : Linker : : SegmentInfo emptySegmentInfo ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation emptyPatchableSegment ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > nonEmptypatchableSegmentData ;
nonEmptypatchableSegmentData . resize ( 64 , 8U ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation nonEmptypatchableSegment { nonEmptypatchableSegmentData . data ( ) , nonEmptypatchableSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 0U ;
relocInfo . symbolName = " aaa " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
linkerInput . dataRelocations . push_back ( relocInfo ) ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : Unknown ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . traits . requiresPatchingOfGlobalVariablesBuffer = true ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
unresolvedExternals . clear ( ) ;
linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
2019-07-04 17:14:51 +02:00
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerTests , givenRelocationTypeWithHighPartOfAddressWhenPatchingDataSegmentsThenLinkerFails ) {
WhiteBox < NEO : : LinkerInput > linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
NEO : : Linker : : SegmentInfo emptySegmentInfo ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation emptyPatchableSegment ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > nonEmptypatchableSegmentData ;
nonEmptypatchableSegmentData . resize ( 64 , 8U ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation nonEmptypatchableSegment { nonEmptypatchableSegmentData . data ( ) , nonEmptypatchableSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 0U ;
relocInfo . symbolName = " aaa " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : AddressHigh ;
linkerInput . dataRelocations . push_back ( relocInfo ) ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . traits . requiresPatchingOfGlobalVariablesBuffer = true ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
linkerInput . dataRelocations [ 0 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : AddressLow ;
unresolvedExternals . clear ( ) ;
linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
}
TEST ( LinkerTests , givenValidSymbolsAndRelocationsThenDataSegmentsAreProperlyPatched ) {
WhiteBox < NEO : : LinkerInput > linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
std : : vector < char > globalConstantsSegmentData ;
globalConstantsSegmentData . resize ( 128 , 7U ) ;
std : : vector < char > globalVariablesSegmentData ;
globalVariablesSegmentData . resize ( 256 , 13U ) ;
NEO : : Linker : : SegmentInfo globalConstantsSegmentInfo , globalVariablesSegmentInfo ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
globalConstantsSegmentInfo . gpuAddress = reinterpret_cast < uintptr_t > ( globalConstantsSegmentData . data ( ) ) ;
globalConstantsSegmentInfo . segmentSize = globalConstantsSegmentData . size ( ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation globalConstantsPatchableSegment { globalConstantsSegmentData . data ( ) , globalConstantsSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
globalVariablesSegmentInfo . gpuAddress = reinterpret_cast < uintptr_t > ( globalVariablesSegmentData . data ( ) ) ;
globalVariablesSegmentInfo . segmentSize = globalVariablesSegmentData . size ( ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation globalVariablesPatchableSegment { globalVariablesSegmentData . data ( ) , globalVariablesSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
NEO : : LinkerInput : : RelocationInfo relocationInfo [ 5 ] ;
// GlobalVar -> GlobalVar
relocationInfo [ 0 ] . offset = 8U ;
relocationInfo [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 0 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalConst -> GlobalVar
relocationInfo [ 1 ] . offset = 24U ;
relocationInfo [ 1 ] . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 1 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 1 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalConst -> GlobalConst
relocationInfo [ 2 ] . offset = 40U ;
relocationInfo [ 2 ] . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 2 ] . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 2 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalVar -> GlobalConst
relocationInfo [ 3 ] . offset = 56U ;
relocationInfo [ 3 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 3 ] . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 3 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalVar Low -> GlobalVar
relocationInfo [ 4 ] . offset = 72 ;
relocationInfo [ 4 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 4 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 4 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : AddressLow ;
uint32_t initValue = 0 ;
for ( const auto & reloc : relocationInfo ) {
linkerInput . addDataRelocationInfo ( reloc ) ;
2020-07-14 16:44:28 +02:00
void * dstRaw = ( reloc . relocationSegment = = NEO : : SegmentType : : GlobalVariables )
? globalVariablesPatchableSegment . getUnderlyingBuffer ( )
: globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ;
2020-01-11 18:25:26 +01:00
if ( reloc . type = = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ) {
* reinterpret_cast < uintptr_t * > ( ptrOffset ( dstRaw , static_cast < size_t > ( reloc . offset ) ) ) = initValue * 4 ; // relocations to global data are currently based on patchIncrement, simulate init data
} else {
* reinterpret_cast < uint32_t * > ( ptrOffset ( dstRaw , static_cast < size_t > ( reloc . offset ) ) ) = initValue * 4 ; // relocations to global data are currently based on patchIncrement, simulate init data
}
+ + initValue ;
}
2020-10-07 15:32:03 +02:00
auto device = std : : unique_ptr < NEO : : MockDevice > ( NEO : : MockDevice : : createWithNewExecutionEnvironment < NEO : : MockDevice > ( NEO : : defaultHwInfo . get ( ) ) ) ;
2020-01-11 18:25:26 +01:00
auto linkResult = linker . link ( globalVariablesSegmentInfo , globalConstantsSegmentInfo , { } ,
2020-07-14 16:44:28 +02:00
& globalVariablesPatchableSegment , & globalConstantsPatchableSegment , { } ,
2020-10-07 15:32:03 +02:00
unresolvedExternals , device . get ( ) , globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ,
globalVariablesPatchableSegment . getUnderlyingBuffer ( ) ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
2020-07-14 16:44:28 +02:00
EXPECT_EQ ( 7U , * reinterpret_cast < uint8_t * > ( globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ) ) ;
EXPECT_EQ ( 13U , * reinterpret_cast < uint8_t * > ( globalVariablesPatchableSegment . getUnderlyingBuffer ( ) ) ) ;
2020-01-11 18:25:26 +01:00
initValue = 0 ;
for ( const auto & reloc : relocationInfo ) {
2020-07-14 16:44:28 +02:00
void * srcRaw = ( reloc . symbolSegment = = NEO : : SegmentType : : GlobalVariables )
? globalVariablesPatchableSegment . getUnderlyingBuffer ( )
: globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ;
void * dstRaw = ( reloc . relocationSegment = = NEO : : SegmentType : : GlobalVariables )
? globalVariablesPatchableSegment . getUnderlyingBuffer ( )
: globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ;
2020-01-11 18:25:26 +01:00
uint8_t * src = reinterpret_cast < uint8_t * > ( srcRaw ) ;
uint8_t * dst = reinterpret_cast < uint8_t * > ( dstRaw ) ;
// make sure no buffer underflow occured
EXPECT_EQ ( dst [ 0 ] , dst [ reloc . offset - 1 ] ) ;
// check patch-incremented value
if ( reloc . type = = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ) {
// make sure no buffer overflow occured
EXPECT_EQ ( dst [ 0 ] , dst [ reloc . offset + sizeof ( uintptr_t ) ] ) ;
EXPECT_EQ ( reinterpret_cast < uintptr_t > ( src ) + initValue * 4 , * reinterpret_cast < uintptr_t * > ( dst + reloc . offset ) ) < < initValue ;
} else {
// make sure no buffer overflow occured
EXPECT_EQ ( dst [ 0 ] , dst [ reloc . offset + sizeof ( uint32_t ) ] ) ;
EXPECT_EQ ( static_cast < uint32_t > ( reinterpret_cast < uintptr_t > ( src ) ) + initValue * 4 , * reinterpret_cast < uint32_t * > ( dst + reloc . offset ) ) < < initValue ;
}
+ + initValue ;
}
}
TEST ( LinkerTests , givenValidSymbolsAndRelocationsWhenPatchin32bitBinaryThenDataSegmentsAreProperlyPatchedWithLowerPartOfTheAddress ) {
WhiteBox < NEO : : LinkerInput > linkerInput ;
linkerInput . setPointerSize ( NEO : : LinkerInput : : Traits : : PointerSize : : Ptr32bit ) ;
NEO : : Linker linker ( linkerInput ) ;
std : : vector < char > globalConstantsSegmentData ;
globalConstantsSegmentData . resize ( 128 , 7U ) ;
std : : vector < char > globalVariablesSegmentData ;
globalVariablesSegmentData . resize ( 256 , 13U ) ;
NEO : : Linker : : SegmentInfo globalConstantsSegmentInfo , globalVariablesSegmentInfo ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
globalConstantsSegmentInfo . gpuAddress = reinterpret_cast < uintptr_t > ( globalConstantsSegmentData . data ( ) ) ;
globalConstantsSegmentInfo . segmentSize = globalConstantsSegmentData . size ( ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation globalConstantsPatchableSegment { globalConstantsSegmentData . data ( ) , globalConstantsSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
globalVariablesSegmentInfo . gpuAddress = reinterpret_cast < uintptr_t > ( globalVariablesSegmentData . data ( ) ) ;
globalVariablesSegmentInfo . segmentSize = globalVariablesSegmentData . size ( ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation globalVariablesPatchableSegment { globalVariablesSegmentData . data ( ) , globalVariablesSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
NEO : : LinkerInput : : RelocationInfo relocationInfo [ 5 ] ;
// GlobalVar -> GlobalVar
relocationInfo [ 0 ] . offset = 8U ;
relocationInfo [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 0 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalConst -> GlobalVar
relocationInfo [ 1 ] . offset = 24U ;
relocationInfo [ 1 ] . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 1 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 1 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalConst -> GlobalConst
relocationInfo [ 2 ] . offset = 40U ;
relocationInfo [ 2 ] . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 2 ] . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 2 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalVar -> GlobalConst
relocationInfo [ 3 ] . offset = 56U ;
relocationInfo [ 3 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 3 ] . symbolSegment = NEO : : SegmentType : : GlobalConstants ;
relocationInfo [ 3 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
// GlobalVar Low -> GlobalVar
relocationInfo [ 4 ] . offset = 72 ;
relocationInfo [ 4 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 4 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
relocationInfo [ 4 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : AddressLow ;
uint32_t initValue = 0 ;
for ( const auto & reloc : relocationInfo ) {
linkerInput . addDataRelocationInfo ( reloc ) ;
2020-07-14 16:44:28 +02:00
void * dstRaw = ( reloc . relocationSegment = = NEO : : SegmentType : : GlobalVariables )
? globalVariablesPatchableSegment . getUnderlyingBuffer ( )
: globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ;
2020-01-11 18:25:26 +01:00
* reinterpret_cast < uint32_t * > ( ptrOffset ( dstRaw , static_cast < size_t > ( reloc . offset ) ) ) = initValue * 4 ; // relocations to global data are currently based on patchIncrement, simulate init data
+ + initValue ;
}
2020-10-07 15:32:03 +02:00
auto device = std : : unique_ptr < NEO : : MockDevice > ( NEO : : MockDevice : : createWithNewExecutionEnvironment < NEO : : MockDevice > ( NEO : : defaultHwInfo . get ( ) ) ) ;
2020-01-11 18:25:26 +01:00
auto linkResult = linker . link ( globalVariablesSegmentInfo , globalConstantsSegmentInfo , { } ,
2020-07-14 16:44:28 +02:00
& globalVariablesPatchableSegment , & globalConstantsPatchableSegment , { } ,
2020-10-07 15:32:03 +02:00
unresolvedExternals , device . get ( ) , globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ,
globalVariablesPatchableSegment . getUnderlyingBuffer ( ) ) ;
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
2020-07-14 16:44:28 +02:00
EXPECT_EQ ( 7U , * reinterpret_cast < uint8_t * > ( globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ) ) ;
EXPECT_EQ ( 13U , * reinterpret_cast < uint8_t * > ( globalVariablesPatchableSegment . getUnderlyingBuffer ( ) ) ) ;
2020-01-11 18:25:26 +01:00
initValue = 0 ;
for ( const auto & reloc : relocationInfo ) {
2020-07-14 16:44:28 +02:00
void * srcRaw = ( reloc . symbolSegment = = NEO : : SegmentType : : GlobalVariables )
? globalVariablesPatchableSegment . getUnderlyingBuffer ( )
: globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ;
void * dstRaw = ( reloc . relocationSegment = = NEO : : SegmentType : : GlobalVariables )
? globalVariablesPatchableSegment . getUnderlyingBuffer ( )
: globalConstantsPatchableSegment . getUnderlyingBuffer ( ) ;
2020-01-11 18:25:26 +01:00
uint8_t * src = reinterpret_cast < uint8_t * > ( srcRaw ) ;
uint8_t * dst = reinterpret_cast < uint8_t * > ( dstRaw ) ;
// make sure no buffer under/overflow occured
EXPECT_EQ ( dst [ 0 ] , dst [ reloc . offset - 1 ] ) ;
EXPECT_EQ ( dst [ 0 ] , dst [ reloc . offset + sizeof ( uint32_t ) ] ) ;
// check patch-incremented value
EXPECT_EQ ( static_cast < uint32_t > ( reinterpret_cast < uintptr_t > ( src ) ) + initValue * 4 , * reinterpret_cast < uint32_t * > ( dst + reloc . offset ) ) < < initValue ;
+ + initValue ;
}
}
TEST ( LinkerTests , givenInvalidRelocationOffsetThenPatchingOfDataSegmentsFails ) {
WhiteBox < NEO : : LinkerInput > linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
NEO : : Linker : : SegmentInfo emptySegmentInfo ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation emptyPatchableSegment ;
2020-01-11 18:25:26 +01:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > nonEmptypatchableSegmentData ;
nonEmptypatchableSegmentData . resize ( 64 , 8U ) ;
2020-07-14 16:44:28 +02:00
NEO : : MockGraphicsAllocation nonEmptypatchableSegment { nonEmptypatchableSegmentData . data ( ) , nonEmptypatchableSegmentData . size ( ) } ;
2020-01-11 18:25:26 +01:00
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 64U ;
relocInfo . symbolName = " aaa " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
linkerInput . dataRelocations . push_back ( relocInfo ) ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . traits . requiresPatchingOfGlobalVariablesBuffer = true ;
2020-07-13 18:42:11 +02:00
auto linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedPartially , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 1U , unresolvedExternals . size ( ) ) ;
linkerInput . dataRelocations [ 0 ] . offset = 32 ;
unresolvedExternals . clear ( ) ;
linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
2020-07-14 16:44:28 +02:00
& nonEmptypatchableSegment , & emptyPatchableSegment , { } ,
unresolvedExternals , nullptr , nullptr , nullptr ) ;
2020-01-11 18:25:26 +01:00
2020-07-13 18:42:11 +02:00
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
2020-01-11 18:25:26 +01:00
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
}
2020-10-08 14:31:53 +02:00
TEST ( LinkerTests , GivenAllocationInLocalMemoryWhichRequiresBlitterWhenPatchingDataSegmentsAllocationThenBlitterIsUsed ) {
DebugManagerStateRestore restorer ;
auto hwInfo = * defaultHwInfo ;
hwInfo . capabilityTable . blitterOperationsSupported = true ;
uint32_t blitsCounter = 0 ;
uint32_t expectedBlitsCount = 0 ;
auto mockBlitMemoryToAllocation = [ & blitsCounter ] ( const Device & device , GraphicsAllocation * memory , size_t offset , const void * hostPtr ,
Vec3 < size_t > size ) - > BlitOperationResult {
blitsCounter + + ;
return BlitOperationResult : : Success ;
} ;
VariableBackup < BlitHelperFunctions : : BlitMemoryToAllocationFunc > blitMemoryToAllocationFuncBackup {
& BlitHelperFunctions : : blitMemoryToAllocation , mockBlitMemoryToAllocation } ;
LocalMemoryAccessMode localMemoryAccessModes [ ] = {
LocalMemoryAccessMode : : Default ,
LocalMemoryAccessMode : : CpuAccessAllowed ,
LocalMemoryAccessMode : : CpuAccessDisallowed } ;
std : : vector < uint8_t > initData ;
initData . resize ( 64 , 7U ) ;
for ( auto localMemoryAccessMode : localMemoryAccessModes ) {
DebugManager . flags . ForceLocalMemoryAccessMode . set ( static_cast < int32_t > ( localMemoryAccessMode ) ) ;
for ( auto isLocalMemorySupported : : : testing : : Bool ( ) ) {
DebugManager . flags . EnableLocalMemory . set ( isLocalMemorySupported ) ;
auto pDevice = std : : unique_ptr < MockDevice > ( MockDevice : : createWithNewExecutionEnvironment < MockDevice > ( & hwInfo ) ) ;
2021-03-08 12:27:14 +00:00
MockSVMAllocsManager svmAllocsManager ( pDevice - > getMemoryManager ( ) , false ) ;
2020-10-08 14:31:53 +02:00
WhiteBox < NEO : : LinkerInput > linkerInput ;
NEO : : Linker linker ( linkerInput ) ;
NEO : : Linker : : SegmentInfo emptySegmentInfo ;
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < char > nonEmptypatchableSegmentData ;
nonEmptypatchableSegmentData . resize ( 64 , 8U ) ;
auto pNonEmptypatchableSegment = allocateGlobalsSurface ( & svmAllocsManager , * pDevice , nonEmptypatchableSegmentData . size ( ) ,
true /* constant */ , nullptr /* linker input */ ,
nonEmptypatchableSegmentData . data ( ) ) ;
NEO : : LinkerInput : : RelocationInfo relocInfo ;
relocInfo . offset = 0U ;
relocInfo . symbolName = " aaa " ;
relocInfo . type = NEO : : LinkerInput : : RelocationInfo : : Type : : Address ;
linkerInput . dataRelocations . push_back ( relocInfo ) ;
linkerInput . dataRelocations [ 0 ] . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . dataRelocations [ 0 ] . symbolSegment = NEO : : SegmentType : : GlobalVariables ;
linkerInput . traits . requiresPatchingOfGlobalVariablesBuffer = true ;
uint64_t initData = 0x1234 ;
auto linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
pNonEmptypatchableSegment , pNonEmptypatchableSegment , { } ,
unresolvedExternals , pDevice . get ( ) , & initData , & initData ) ;
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
linkerInput . dataRelocations [ 0 ] . type = NEO : : LinkerInput : : RelocationInfo : : Type : : AddressLow ;
linkResult = linker . link ( emptySegmentInfo , emptySegmentInfo , emptySegmentInfo ,
pNonEmptypatchableSegment , pNonEmptypatchableSegment , { } ,
unresolvedExternals , pDevice . get ( ) , & initData , & initData ) ;
EXPECT_EQ ( NEO : : LinkingStatus : : LinkedFully , linkResult ) ;
EXPECT_EQ ( 0U , unresolvedExternals . size ( ) ) ;
if ( pNonEmptypatchableSegment - > isAllocatedInLocalMemoryPool ( ) & &
( localMemoryAccessMode = = LocalMemoryAccessMode : : CpuAccessDisallowed ) ) {
auto blitsOnAllocationInitialization = 1 ;
auto blitsOnPatchingDataSegments = 2 ;
expectedBlitsCount + = blitsOnAllocationInitialization + blitsOnPatchingDataSegments ;
}
EXPECT_EQ ( expectedBlitsCount , blitsCounter ) ;
pDevice - > getMemoryManager ( ) - > freeGraphicsMemory ( pNonEmptypatchableSegment ) ;
}
}
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerErrorMessageTests , whenListOfUnresolvedExternalsIsEmptyThenErrorTypeDefaultsToInternalError ) {
2019-07-04 17:14:51 +02:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < std : : string > segmentsNames { " kernel1 " , " kernel2 " } ;
auto err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , segmentsNames ) ;
EXPECT_EQ ( std : : string ( " Internal linker error " ) , err ) ;
}
2020-01-11 18:25:26 +01:00
TEST ( LinkerErrorMessageTests , givenListOfUnresolvedExternalsThenSymbolNameOrSymbolSegmentTypeGetsEmbededInErrorMessage ) {
2019-07-04 17:14:51 +02:00
NEO : : Linker : : UnresolvedExternals unresolvedExternals ;
std : : vector < std : : string > segmentsNames { " kernel1 " , " kernel2 " } ;
NEO : : Linker : : UnresolvedExternal unresolvedExternal = { } ;
unresolvedExternal . instructionsSegmentId = 1 ;
unresolvedExternal . internalError = false ;
unresolvedExternal . unresolvedRelocation . offset = 64 ;
unresolvedExternal . unresolvedRelocation . symbolName = " arrayABC " ;
2020-01-11 18:25:26 +01:00
unresolvedExternal . unresolvedRelocation . relocationSegment = NEO : : SegmentType : : Instructions ;
2019-07-04 17:14:51 +02:00
unresolvedExternals . push_back ( unresolvedExternal ) ;
auto err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , segmentsNames ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( unresolvedExternal . unresolvedRelocation . symbolName . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( segmentsNames [ unresolvedExternal . instructionsSegmentId ] . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( std : : to_string ( unresolvedExternal . unresolvedRelocation . offset ) . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : Not ( : : testing : : HasSubstr ( " internal error " ) ) ) ;
unresolvedExternals [ 0 ] . internalError = true ;
err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , segmentsNames ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( unresolvedExternal . unresolvedRelocation . symbolName . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( segmentsNames [ unresolvedExternal . instructionsSegmentId ] . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( std : : to_string ( unresolvedExternal . unresolvedRelocation . offset ) . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( " internal linker error " ) ) ;
err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , { } ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( unresolvedExternal . unresolvedRelocation . symbolName . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : Not ( : : testing : : HasSubstr ( segmentsNames [ unresolvedExternal . instructionsSegmentId ] . c_str ( ) ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( std : : to_string ( unresolvedExternal . unresolvedRelocation . offset ) . c_str ( ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( " internal linker error " ) ) ;
2020-01-11 18:25:26 +01:00
unresolvedExternals [ 0 ] . unresolvedRelocation . relocationSegment = NEO : : SegmentType : : GlobalConstants ;
err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , { } ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( NEO : : asString ( NEO : : SegmentType : : GlobalConstants ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( std : : to_string ( unresolvedExternal . unresolvedRelocation . offset ) . c_str ( ) ) ) ;
unresolvedExternals [ 0 ] . unresolvedRelocation . relocationSegment = NEO : : SegmentType : : GlobalVariables ;
err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , { } ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( NEO : : asString ( NEO : : SegmentType : : GlobalVariables ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( std : : to_string ( unresolvedExternal . unresolvedRelocation . offset ) . c_str ( ) ) ) ;
unresolvedExternals [ 0 ] . unresolvedRelocation . relocationSegment = NEO : : SegmentType : : Unknown ;
err = NEO : : constructLinkerErrorMessage ( unresolvedExternals , { } ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( NEO : : asString ( NEO : : SegmentType : : Unknown ) ) ) ;
EXPECT_THAT ( err . c_str ( ) , : : testing : : HasSubstr ( std : : to_string ( unresolvedExternal . unresolvedRelocation . offset ) . c_str ( ) ) ) ;
2019-07-04 17:14:51 +02:00
}
2020-04-28 14:00:15 +02:00
2021-01-05 11:58:19 +01:00
TEST ( RelocationsDebugMessageTests , givenEmptyListOfRelocatedSymbolsThenReturnsEmptyString ) {
2020-04-28 14:00:15 +02:00
auto message = NEO : : constructRelocationsDebugMessage ( { } ) ;
EXPECT_EQ ( 0U , message . size ( ) ) < < message ;
}
2021-01-05 11:58:19 +01:00
TEST ( RelocationsDebugMessageTests , givenListOfRelocatedSymbolsThenReturnProperDebugMessage ) {
2020-04-28 14:00:15 +02:00
NEO : : Linker : : RelocatedSymbolsMap symbols ;
auto & funcSymbol = symbols [ " foo " ] ;
auto & constDataSymbol = symbols [ " constInt " ] ;
auto & globalVarSymbol = symbols [ " intX " ] ;
funcSymbol . symbol . segment = NEO : : SegmentType : : Instructions ;
funcSymbol . symbol . offset = 64U ;
funcSymbol . symbol . size = 1024U ;
funcSymbol . gpuAddress = 4096U ;
constDataSymbol . symbol . segment = NEO : : SegmentType : : GlobalConstants ;
constDataSymbol . symbol . offset = 32U ;
constDataSymbol . symbol . size = 16U ;
constDataSymbol . gpuAddress = 8U ;
globalVarSymbol . symbol . segment = NEO : : SegmentType : : GlobalVariables ;
globalVarSymbol . symbol . offset = 72U ;
globalVarSymbol . symbol . size = 8U ;
globalVarSymbol . gpuAddress = 256U ;
auto message = NEO : : constructRelocationsDebugMessage ( symbols ) ;
std : : stringstream expected ;
expected < < " Relocations debug informations : \n " ;
for ( const auto & symbol : symbols ) {
if ( symbol . first = = " foo " ) {
expected < < " * \" foo \" [1024 bytes] INSTRUCTIONS_SEGMENT@64 -> 0x1000 GPUVA \n " ;
} else if ( symbol . first = = " constInt " ) {
expected < < " * \" constInt \" [16 bytes] GLOBAL_CONSTANTS_SEGMENT@32 -> 0x8 GPUVA \n " ;
} else {
expected < < " * \" intX \" [8 bytes] GLOBAL_VARIABLES_SEGMENT@72 -> 0x100 GPUVA \n " ;
}
}
EXPECT_STREQ ( expected . str ( ) . c_str ( ) , message . c_str ( ) ) ;
}
2021-02-09 14:57:16 +00:00
TEST ( LinkerTests , GivenDebugDataWhenApplyingDebugDataRelocationsThenRelocationsAreAppliedInMemory ) {
NEO : : Elf : : ElfFileHeader < NEO : : Elf : : EI_CLASS_64 > header ;
header . shOff = header . ehSize ;
header . shNum = 4 ;
header . shStrNdx = 0 ;
NEO : : Elf : : ElfSectionHeader < NEO : : Elf : : EI_CLASS_64 > sectionHeader0 ;
sectionHeader0 . size = 80 ;
sectionHeader0 . offset = 80 ;
NEO : : Elf : : ElfSectionHeader < NEO : : Elf : : EI_CLASS_64 > sectionHeader1 ;
sectionHeader1 . size = 80 ;
sectionHeader1 . offset = 160 ;
NEO : : Elf : : ElfSectionHeader < NEO : : Elf : : EI_CLASS_64 > sectionHeader2 ;
sectionHeader2 . size = 80 ;
sectionHeader2 . offset = 240 ;
NEO : : Elf : : ElfSectionHeader < NEO : : Elf : : EI_CLASS_64 > sectionHeader3 ;
sectionHeader3 . size = 80 ;
sectionHeader3 . offset = 320 ;
NEO : : Elf : : ElfSectionHeader < NEO : : Elf : : EI_CLASS_64 > sectionHeader4 ;
sectionHeader4 . size = 80 ;
sectionHeader4 . offset = 400 ;
MockElf < NEO : : Elf : : EI_CLASS_64 > elf64 ;
elf64 . elfFileHeader = & header ;
uint64_t dummyData [ 100 ] ;
uint8_t * storage = reinterpret_cast < uint8_t * > ( dummyData ) ;
elf64 . sectionHeaders . push_back ( { & sectionHeader0 , { & storage [ 80 ] , 80 } } ) ;
elf64 . sectionHeaders . push_back ( { & sectionHeader1 , { & storage [ 160 ] , 80 } } ) ;
elf64 . sectionHeaders . push_back ( { & sectionHeader2 , { & storage [ 240 ] , 80 } } ) ;
elf64 . sectionHeaders . push_back ( { & sectionHeader3 , { & storage [ 320 ] , 80 } } ) ;
elf64 . sectionHeaders . push_back ( { & sectionHeader4 , { & storage [ 400 ] , 80 } } ) ;
std : : unordered_map < uint32_t , std : : string > sectionNames ;
sectionNames [ 0 ] = " .text " ;
sectionNames [ 1 ] = " .data.global " ;
sectionNames [ 2 ] = " .debug_info " ;
sectionNames [ 3 ] = " .debug_abbrev " ;
sectionNames [ 4 ] = " .debug_line " ;
2021-03-15 15:18:17 +00:00
sectionNames [ 5 ] = " .data.const " ;
2021-02-09 14:57:16 +00:00
elf64 . setupSecionNames ( std : : move ( sectionNames ) ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc0 = { } ;
reloc0 . offset = 64 ;
reloc0 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc0 . symbolName = " .debug_abbrev " ;
reloc0 . symbolSectionIndex = 3 ;
reloc0 . symbolTableIndex = 0 ;
reloc0 . targetSectionIndex = 2 ;
reloc0 . addend = 0 ;
elf64 . debugInfoRelocations . emplace_back ( reloc0 ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc1 = { } ;
reloc1 . offset = 32 ;
reloc1 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_32 ) ;
reloc1 . symbolName = " .debug_line " ;
reloc1 . symbolSectionIndex = 4 ;
reloc1 . symbolTableIndex = 0 ;
reloc1 . targetSectionIndex = 2 ;
reloc1 . addend = 4 ;
elf64 . debugInfoRelocations . emplace_back ( reloc1 ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc2 = { } ;
reloc2 . offset = 32 ;
reloc2 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc2 . symbolName = " .text " ;
reloc2 . symbolSectionIndex = 0 ;
reloc2 . symbolTableIndex = 0 ;
reloc2 . targetSectionIndex = 4 ;
reloc2 . addend = 18 ;
elf64 . debugInfoRelocations . emplace_back ( reloc2 ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc3 = { } ;
reloc3 . offset = 0 ;
reloc3 . relocType = static_cast < uint32_t > ( Elf : : RELOCATION_X8664_TYPE : : R_X8664_64 ) ;
reloc3 . symbolName = " .data " ;
reloc3 . symbolSectionIndex = 1 ;
reloc3 . symbolTableIndex = 0 ;
reloc3 . targetSectionIndex = 4 ;
reloc3 . addend = 55 ;
elf64 . debugInfoRelocations . emplace_back ( reloc3 ) ;
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc4 = { } ;
reloc4 . offset = 8 ;
reloc4 . relocType = static_cast < uint32_t > ( 0 ) ;
reloc4 . symbolName = " .text " ;
reloc4 . symbolSectionIndex = 0 ;
reloc4 . symbolTableIndex = 0 ;
reloc4 . targetSectionIndex = 4 ;
reloc4 . addend = 77 ;
elf64 . debugInfoRelocations . emplace_back ( reloc4 ) ;
2021-03-15 15:18:17 +00:00
NEO : : Elf : : Elf < NEO : : Elf : : EI_CLASS_64 > : : RelocationInfo reloc5 = { } ;
reloc5 . offset = 16 ;
reloc5 . relocType = static_cast < uint32_t > ( 1 ) ;
reloc5 . symbolName = " .data.const " ;
reloc5 . symbolSectionIndex = 5 ;
reloc5 . symbolTableIndex = 0 ;
reloc5 . targetSectionIndex = 4 ;
reloc5 . addend = 20 ;
elf64 . debugInfoRelocations . emplace_back ( reloc5 ) ;
2021-02-09 14:57:16 +00:00
uint64_t * relocInDebugLine = reinterpret_cast < uint64_t * > ( & storage [ 400 ] ) ;
* relocInDebugLine = 0 ;
uint64_t * relocInDebugLine2 = reinterpret_cast < uint64_t * > ( & storage [ 408 ] ) ;
* relocInDebugLine2 = 0 ;
2021-03-15 15:18:17 +00:00
uint64_t * relocInDebugLine5 = reinterpret_cast < uint64_t * > ( & storage [ 416 ] ) ;
* relocInDebugLine5 = 0 ;
2021-02-09 14:57:16 +00:00
NEO : : Elf : : ElfSymbolEntry < NEO : : Elf : : EI_CLASS_64 > symbol ;
symbol . value = 0 ;
elf64 . symbolTable . push_back ( symbol ) ;
NEO : : Linker : : SegmentInfo text = { static_cast < uintptr_t > ( 0x80001000 ) , 0x10000 } ;
NEO : : Linker : : SegmentInfo dataGlobal = { static_cast < uintptr_t > ( 0x123000 ) , 0x10000 } ;
NEO : : Linker : : SegmentInfo dataConst = { static_cast < uintptr_t > ( 0xabc000 ) , 0x10000 } ;
NEO : : Linker : : applyDebugDataRelocations ( elf64 , { storage , sizeof ( dummyData ) } , text , dataGlobal , dataConst ) ;
auto reloc0Location = reinterpret_cast < const uint64_t * > ( & elf64 . sectionHeaders [ reloc0 . targetSectionIndex ] . data [ static_cast < size_t > ( reloc0 . offset ) ] ) ;
auto reloc1Location = reinterpret_cast < const uint32_t * > ( & elf64 . sectionHeaders [ reloc1 . targetSectionIndex ] . data [ static_cast < size_t > ( reloc1 . offset ) ] ) ;
auto reloc2Location = reinterpret_cast < const uint64_t * > ( & elf64 . sectionHeaders [ reloc2 . targetSectionIndex ] . data [ static_cast < size_t > ( reloc2 . offset ) ] ) ;
auto reloc3Location = reinterpret_cast < const uint64_t * > ( & elf64 . sectionHeaders [ reloc3 . targetSectionIndex ] . data [ static_cast < size_t > ( reloc3 . offset ) ] ) ;
auto reloc4Location = reinterpret_cast < const uint64_t * > ( & elf64 . sectionHeaders [ reloc4 . targetSectionIndex ] . data [ static_cast < size_t > ( reloc4 . offset ) ] ) ;
2021-03-15 15:18:17 +00:00
auto reloc5Location = reinterpret_cast < const uint64_t * > ( & elf64 . sectionHeaders [ reloc5 . targetSectionIndex ] . data [ static_cast < size_t > ( reloc5 . offset ) ] ) ;
2021-02-09 14:57:16 +00:00
2021-03-15 15:18:17 +00:00
uint64_t expectedValue0 = reloc0 . addend ;
uint64_t expectedValue1 = reloc1 . addend ;
2021-02-09 14:57:16 +00:00
auto expectedValue2 = uint64_t ( 0x80001000 ) + reloc2 . addend ;
2021-03-15 15:18:17 +00:00
uint64_t expectedValue3 = dataGlobal . gpuAddress + reloc3 . addend ;
uint64_t expectedValue5 = dataConst . gpuAddress + reloc5 . addend ;
2021-02-09 14:57:16 +00:00
EXPECT_EQ ( expectedValue0 , * reloc0Location ) ;
EXPECT_EQ ( expectedValue1 , * reloc1Location ) ;
EXPECT_EQ ( expectedValue2 , * reloc2Location ) ;
EXPECT_EQ ( expectedValue3 , * reloc3Location ) ;
EXPECT_EQ ( 0u , * reloc4Location ) ;
2021-03-15 15:18:17 +00:00
EXPECT_EQ ( expectedValue5 , * reloc5Location ) ;
2021-02-09 14:57:16 +00:00
}