diff --git a/core/compiler_interface/linker.cpp b/core/compiler_interface/linker.cpp index 002c26b5b7..a5b0386e9a 100644 --- a/core/compiler_interface/linker.cpp +++ b/core/compiler_interface/linker.cpp @@ -7,38 +7,11 @@ #include "linker.h" +#include "common/compiler_support.h" #include "core/helpers/debug_helpers.h" #include "core/helpers/ptr_math.h" -#if __has_include("RelocationInfo.h") #include "RelocationInfo.h" -#else -namespace vISA { -static const uint32_t MAX_SYMBOL_NAME_LENGTH = 256; - -enum GenSymType { S_NOTYPE = 0, - S_UNDEF = 1, - S_FUNC = 2, - S_GLOBAL_VAR = 3, - S_GLOBAL_VAR_CONST = 4 }; - -typedef struct { - uint32_t s_type; - uint32_t s_offset; - uint32_t s_size; - char s_name[MAX_SYMBOL_NAME_LENGTH]; -} GenSymEntry; - -enum GenRelocType { R_NONE = 0, - R_SYM_ADDR = 1 }; - -typedef struct { - uint32_t r_type; - uint32_t r_offset; - char r_symbol[MAX_SYMBOL_NAME_LENGTH]; -} GenRelocEntry; -} // namespace vISA -#endif #include @@ -121,6 +94,13 @@ bool LinkerInput::decodeRelocationTable(const void *data, uint32_t numEntries, u DEBUG_BREAK_IF(true); return false; case vISA::R_SYM_ADDR: + relocInfo.type = RelocationInfo::Type::Address; + break; + case vISA::R_SYM_ADDR_32: + relocInfo.type = RelocationInfo::Type::AddressLow; + break; + case vISA::R_SYM_ADDR_32_HI: + relocInfo.type = RelocationInfo::Type::AddressHigh; break; } outRelocInfo.push_back(std::move(relocInfo)); @@ -181,7 +161,19 @@ bool Linker::patchInstructionsSegments(const std::vector &inst continue; } - *reinterpret_cast(relocAddress) = symbolIt->second.gpuAddress; + uint64_t gpuAddressAs64bit = static_cast(symbolIt->second.gpuAddress); + switch (relocation.type) { + default: + UNRECOVERABLE_IF(RelocationInfo::Type::Address != relocation.type); + *reinterpret_cast(relocAddress) = symbolIt->second.gpuAddress; + break; + case RelocationInfo::Type::AddressLow: + *reinterpret_cast(relocAddress) = static_cast(gpuAddressAs64bit & 0xffffffff); + break; + case RelocationInfo::Type::AddressHigh: + *reinterpret_cast(relocAddress) = static_cast((gpuAddressAs64bit >> 32) & 0xffffffff); + break; + } } } outUnresolvedExternals.swap(unresolvedExternals); diff --git a/core/compiler_interface/linker.h b/core/compiler_interface/linker.h index 431a6cbbd2..327ad6d586 100644 --- a/core/compiler_interface/linker.h +++ b/core/compiler_interface/linker.h @@ -29,6 +29,7 @@ struct SymbolInfo { }; struct LinkerInput { + union Traits { Traits() : packed(0) { } @@ -43,8 +44,16 @@ struct LinkerInput { static_assert(sizeof(Traits) == sizeof(Traits::packed), ""); struct RelocationInfo { + enum class Type : uint32_t { + Unknown, + Address, + AddressHigh, + AddressLow + }; + std::string symbolName; uint32_t offset = std::numeric_limits::max(); + Type type = Type::Unknown; }; using Relocations = std::vector; diff --git a/core/unit_tests/compiler_interface/linker_tests.cpp b/core/unit_tests/compiler_interface/linker_tests.cpp index a75c7e0f14..6bb7e987c0 100644 --- a/core/unit_tests/compiler_interface/linker_tests.cpp +++ b/core/unit_tests/compiler_interface/linker_tests.cpp @@ -11,39 +11,7 @@ #include -#if __has_include("RelocationInfo.h") #include "RelocationInfo.h" -#else -namespace vISA { -static const uint32_t MAX_SYMBOL_NAME_LENGTH = 256; - -enum GenSymType { - S_NOTYPE = 0, - S_UNDEF = 1, - S_FUNC = 2, - S_GLOBAL_VAR = 3, - S_GLOBAL_VAR_CONST = 4 -}; - -typedef struct { - uint32_t s_type; - uint32_t s_offset; - uint32_t s_size; - char s_name[MAX_SYMBOL_NAME_LENGTH]; -} GenSymEntry; - -enum GenRelocType { - R_NONE = 0, - R_SYM_ADDR = 1 -}; - -typedef struct { - uint32_t r_type; - uint32_t r_offset; - char r_symbol[MAX_SYMBOL_NAME_LENGTH]; -} GenRelocEntry; -} // namespace vISA -#endif TEST(LinkerInputTests, givenGlobalsSymbolTableThenProperlyDecodesGlobalVariablesAndGlobalConstants) { NEO::LinkerInput linkerInput; @@ -316,8 +284,18 @@ TEST(LinkerTests, givenValidSymbolsAndRelocationsThenInstructionSegmentsArePrope relocC.r_offset = 16; relocC.r_type = vISA::GenRelocType::R_SYM_ADDR; - vISA::GenRelocEntry relocs[] = {relocA, relocB, relocC}; - bool decodeRelocSuccess = linkerInput.decodeRelocationTable(&relocs, 3, 0); + 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; + + vISA::GenRelocEntry relocs[] = {relocA, relocB, relocC, relocCPartHigh, relocCPartLow}; + bool decodeRelocSuccess = linkerInput.decodeRelocationTable(&relocs, 5, 0); EXPECT_TRUE(decodeRelocSuccess); NEO::Linker linker(linkerInput); @@ -331,7 +309,8 @@ TEST(LinkerTests, givenValidSymbolsAndRelocationsThenInstructionSegmentsArePrope NEO::Linker::UnresolvedExternals unresolvedExternals; std::vector instructionSegment; - instructionSegment.resize(64, 0); + uint32_t initData = 0x77777777; + instructionSegment.resize(64, static_cast(initData)); NEO::Linker::PatchableSegment seg0; seg0.hostPointer = instructionSegment.data(); seg0.segmentSize = instructionSegment.size(); @@ -355,6 +334,17 @@ TEST(LinkerTests, givenValidSymbolsAndRelocationsThenInstructionSegmentsArePrope EXPECT_EQ(relocatedSymbols[symGlobalVariable.s_name].gpuAddress, *reinterpret_cast(instructionSegment.data() + relocA.r_offset)); EXPECT_EQ(relocatedSymbols[symGlobalConstant.s_name].gpuAddress, *reinterpret_cast(instructionSegment.data() + relocB.r_offset)); EXPECT_EQ(relocatedSymbols[symExportedFunc.s_name].gpuAddress, *reinterpret_cast(instructionSegment.data() + relocC.r_offset)); + + auto funcGpuAddressAs64bit = static_cast(relocatedSymbols[symExportedFunc.s_name].gpuAddress); + auto funcAddressLow = static_cast(funcGpuAddressAs64bit & 0xffffffff); + auto funcAddressHigh = static_cast((funcGpuAddressAs64bit >> 32) & 0xffffffff); + EXPECT_EQ(funcAddressLow, *reinterpret_cast(instructionSegment.data() + relocCPartLow.r_offset)); + EXPECT_EQ(initData, *reinterpret_cast(instructionSegment.data() + relocCPartLow.r_offset - sizeof(uint32_t))); + EXPECT_EQ(initData, *reinterpret_cast(instructionSegment.data() + relocCPartLow.r_offset + sizeof(uint32_t))); + + EXPECT_EQ(funcAddressHigh, *reinterpret_cast(instructionSegment.data() + relocCPartHigh.r_offset)); + EXPECT_EQ(initData, *reinterpret_cast(instructionSegment.data() + relocCPartHigh.r_offset - sizeof(uint32_t))); + EXPECT_EQ(initData, *reinterpret_cast(instructionSegment.data() + relocCPartHigh.r_offset + sizeof(uint32_t))); } TEST(LinkerTests, givenInvalidSymbolOffsetThenRelocationFails) { diff --git a/unit_tests/program/program_data_tests.cpp b/unit_tests/program/program_data_tests.cpp index 4d44853e9d..fffc292a47 100644 --- a/unit_tests/program/program_data_tests.cpp +++ b/unit_tests/program/program_data_tests.cpp @@ -876,7 +876,10 @@ TEST_F(ProgramDataTest, whenLinkerInputValidThenIsaIsProperlyPatched) { linkerInput->symbols["B"] = NEO::SymbolInfo{8U, 4U, NEO::SymbolInfo::GlobalConstant}; linkerInput->symbols["C"] = NEO::SymbolInfo{16U, 4U, NEO::SymbolInfo::Function}; - linkerInput->relocations.push_back({NEO::LinkerInput::RelocationInfo{"A", 8U}, NEO::LinkerInput::RelocationInfo{"B", 16U}, NEO::LinkerInput::RelocationInfo{"C", 24U}}); + auto relocationType = NEO::LinkerInput::RelocationInfo::Type::Address; + linkerInput->relocations.push_back({NEO::LinkerInput::RelocationInfo{"A", 8U, relocationType}, + NEO::LinkerInput::RelocationInfo{"B", 16U, relocationType}, + NEO::LinkerInput::RelocationInfo{"C", 24U, relocationType}}); linkerInput->traits.requiresPatchingOfInstructionSegments = true; linkerInput->exportedFunctionsSegmentId = 0; NEO::ExecutionEnvironment env;