diff --git a/level_zero/core/source/module/module_imp.cpp b/level_zero/core/source/module/module_imp.cpp index 0f2d21e6ca..353ebdd8f3 100644 --- a/level_zero/core/source/module/module_imp.cpp +++ b/level_zero/core/source/module/module_imp.cpp @@ -854,11 +854,12 @@ bool ModuleImp::linkBinary() { if (linkerInput->getTraits().requiresPatchingOfInstructionSegments) { patchedIsaTempStorage.reserve(this->kernelImmDatas.size()); kernelDescriptors.reserve(this->kernelImmDatas.size()); - for (const auto &kernelInfo : this->translationUnit->programInfo.kernelInfos) { + for (size_t i = 0; i < kernelImmDatas.size(); i++) { + auto kernelInfo = this->translationUnit->programInfo.kernelInfos.at(i); auto &kernHeapInfo = kernelInfo->heapInfo; const char *originalIsa = reinterpret_cast(kernHeapInfo.pKernelHeap); patchedIsaTempStorage.push_back(std::vector(originalIsa, originalIsa + kernHeapInfo.KernelHeapSize)); - isaSegmentsForPatching.push_back(Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), kernHeapInfo.KernelHeapSize}); + isaSegmentsForPatching.push_back(Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), static_cast(kernelImmDatas.at(i)->getIsaGraphicsAllocation()->getGpuAddressToPatch()), kernHeapInfo.KernelHeapSize, kernelInfo->kernelDescriptor.kernelMetadata.kernelName}); kernelDescriptors.push_back(&kernelInfo->kernelDescriptor); } } @@ -1084,11 +1085,12 @@ ze_result_t ModuleImp::performDynamicLink(uint32_t numModules, if (moduleId->translationUnit->programInfo.linkerInput && moduleId->translationUnit->programInfo.linkerInput->getTraits().requiresPatchingOfInstructionSegments) { if (patchedIsaTempStorage.empty()) { patchedIsaTempStorage.reserve(moduleId->kernelImmDatas.size()); - for (const auto &kernelInfo : moduleId->translationUnit->programInfo.kernelInfos) { + for (size_t i = 0; i < kernelImmDatas.size(); i++) { + const auto kernelInfo = this->translationUnit->programInfo.kernelInfos.at(i); auto &kernHeapInfo = kernelInfo->heapInfo; const char *originalIsa = reinterpret_cast(kernHeapInfo.pKernelHeap); patchedIsaTempStorage.push_back(std::vector(originalIsa, originalIsa + kernHeapInfo.KernelHeapSize)); - isaSegmentsForPatching.push_back(NEO::Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), kernHeapInfo.KernelHeapSize}); + isaSegmentsForPatching.push_back(NEO::Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), static_cast(kernelImmDatas.at(i)->getIsaGraphicsAllocation()->getGpuAddressToPatch()), kernHeapInfo.KernelHeapSize, kernelInfo->kernelDescriptor.kernelMetadata.kernelName}); } } for (const auto &unresolvedExternal : moduleId->unresolvedExternalsInfo) { diff --git a/level_zero/core/test/unit_tests/sources/debugger/test_module_with_debug.cpp b/level_zero/core/test/unit_tests/sources/debugger/test_module_with_debug.cpp index 5ab67cdffe..84a858bf48 100644 --- a/level_zero/core/test/unit_tests/sources/debugger/test_module_with_debug.cpp +++ b/level_zero/core/test/unit_tests/sources/debugger/test_module_with_debug.cpp @@ -994,7 +994,7 @@ HWTEST_F(NotifyModuleLoadTest, givenDebuggingEnabledWhenModuleWithUnresolvedSymb } NEO::SymbolInfo symbolInfo{}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; auto module1 = std::make_unique(device, nullptr, ModuleType::User); diff --git a/level_zero/core/test/unit_tests/sources/module/test_module.cpp b/level_zero/core/test/unit_tests/sources/module/test_module.cpp index 65476e6c70..6c3aa85a59 100644 --- a/level_zero/core/test/unit_tests/sources/module/test_module.cpp +++ b/level_zero/core/test/unit_tests/sources/module/test_module.cpp @@ -1212,7 +1212,7 @@ TEST_F(ModuleDynamicLinkTests, givenModuleWithUnresolvedSymbolWhenTheOtherModule unresolvedExternal.unresolvedRelocation = unresolvedRelocation; NEO::SymbolInfo symbolInfo{}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1258,7 +1258,7 @@ TEST_F(ModuleDynamicLinkTests, givenModuleWithUnresolvedSymbolWhenTheOtherModule unresolvedExternal.unresolvedRelocation = unresolvedRelocation; NEO::SymbolInfo symbolInfo{}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1320,13 +1320,13 @@ TEST_F(ModuleDynamicLinkTests, givenMultipleModulesWithUnresolvedSymbolWhenTheEa unresolvedExternalChained.unresolvedRelocation = unresolvedRelocationChained; NEO::SymbolInfo module0SymbolInfo{}; - NEO::Linker::RelocatedSymbol module0RelocatedSymbol{module0SymbolInfo, gpuAddress0}; + NEO::Linker::RelocatedSymbol module0RelocatedSymbol{module0SymbolInfo, gpuAddress0}; NEO::SymbolInfo module1SymbolInfo{}; - NEO::Linker::RelocatedSymbol module1RelocatedSymbol{module1SymbolInfo, gpuAddress1}; + NEO::Linker::RelocatedSymbol module1RelocatedSymbol{module1SymbolInfo, gpuAddress1}; NEO::SymbolInfo module2SymbolInfo{}; - NEO::Linker::RelocatedSymbol module2RelocatedSymbol{module2SymbolInfo, gpuAddress2}; + NEO::Linker::RelocatedSymbol module2RelocatedSymbol{module2SymbolInfo, gpuAddress2}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1464,13 +1464,13 @@ TEST_F(ModuleDynamicLinkTests, givenMultipleModulesWithUnresolvedSymbolWhenTheEa unresolvedExternalChained.unresolvedRelocation = unresolvedRelocationChained; NEO::SymbolInfo module0SymbolInfo{}; - NEO::Linker::RelocatedSymbol module0RelocatedSymbol{module0SymbolInfo, gpuAddress0}; + NEO::Linker::RelocatedSymbol module0RelocatedSymbol{module0SymbolInfo, gpuAddress0}; NEO::SymbolInfo module1SymbolInfo{}; - NEO::Linker::RelocatedSymbol module1RelocatedSymbol{module1SymbolInfo, gpuAddress1}; + NEO::Linker::RelocatedSymbol module1RelocatedSymbol{module1SymbolInfo, gpuAddress1}; NEO::SymbolInfo module2SymbolInfo{}; - NEO::Linker::RelocatedSymbol module2RelocatedSymbol{module2SymbolInfo, gpuAddress2}; + NEO::Linker::RelocatedSymbol module2RelocatedSymbol{module2SymbolInfo, gpuAddress2}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1550,10 +1550,10 @@ TEST_F(ModuleDynamicLinkTests, givenModuleWithUnresolvedSymbolWhenTheOtherModule unresolvedExternal2.unresolvedRelocation = unresolvedRelocation2; NEO::SymbolInfo symbolInfo{}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; NEO::SymbolInfo symbolInfo2{}; - NEO::Linker::RelocatedSymbol relocatedSymbol2{symbolInfo2, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol2{symbolInfo2, gpuAddress}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1732,7 +1732,7 @@ TEST_F(ModuleFunctionPointerTests, givenModuleWithExportedSymbolThenGetFunctionP NEO::SymbolInfo symbolInfo{}; symbolInfo.segment = NEO::SegmentType::Instructions; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1762,7 +1762,7 @@ TEST_F(ModuleFunctionPointerTests, givenInvalidFunctionNameAndModuleWithExported NEO::SymbolInfo symbolInfo{}; symbolInfo.segment = NEO::SegmentType::Instructions; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -1795,7 +1795,7 @@ TEST_F(ModuleFunctionPointerTests, givenModuleWithExportedSymbolThenGetFunctionP NEO::SymbolInfo symbolInfo{}; symbolInfo.segment = NEO::SegmentType::Instructions; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; char kernelHeap[MemoryConstants::pageSize] = {}; @@ -2711,7 +2711,7 @@ TEST_F(ModuleTest, givenModuleWithSymbolWhenGettingGlobalPointerThenSizeAndPoint uint64_t gpuAddress = 0x12345000; NEO::SymbolInfo symbolInfo{0, 1024u, SegmentType::GlobalVariables}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; auto module0 = std::make_unique(device, nullptr, ModuleType::User); module0->symbols["symbol"] = relocatedSymbol; @@ -2729,7 +2729,7 @@ TEST_F(ModuleTest, givenModuleWithSymbolWhenGettingGlobalPointerWithNullptrInput uint64_t gpuAddress = 0x12345000; NEO::SymbolInfo symbolInfo{0, 1024u, SegmentType::GlobalVariables}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; auto module0 = std::make_unique(device, nullptr, ModuleType::User); module0->symbols["symbol"] = relocatedSymbol; @@ -2747,11 +2747,11 @@ TEST_F(ModuleTest, givenModuleWithGlobalSymbolMapWhenGettingGlobalPointerByHostS size_t symbolsSize = 1024u; uint64_t globalVarGpuAddress = 0x12345000; NEO::SymbolInfo globalVariablesSymbolInfo{0, static_cast(symbolsSize), SegmentType::GlobalVariables}; - NEO::Linker::RelocatedSymbol globalVariablesRelocatedSymbol{globalVariablesSymbolInfo, globalVarGpuAddress}; + NEO::Linker::RelocatedSymbol globalVariablesRelocatedSymbol{globalVariablesSymbolInfo, globalVarGpuAddress}; uint64_t globalConstGpuAddress = 0x12347000; NEO::SymbolInfo globalConstantsSymbolInfo{0, static_cast(symbolsSize), SegmentType::GlobalConstants}; - NEO::Linker::RelocatedSymbol globalConstansRelocatedSymbol{globalConstantsSymbolInfo, globalConstGpuAddress}; + NEO::Linker::RelocatedSymbol globalConstansRelocatedSymbol{globalConstantsSymbolInfo, globalConstGpuAddress}; auto module0 = std::make_unique(device, nullptr, ModuleType::User); module0->symbols["devSymbolOne"] = globalVariablesRelocatedSymbol; @@ -2797,7 +2797,7 @@ TEST_F(ModuleTest, givenModuleWithGlobalSymbolsMapWhenPopulatingMapWithSymbolFro size_t symbolSize = 1024u; uint64_t gpuAddress = 0x12345000; NEO::SymbolInfo symbolInfo{0, static_cast(symbolSize), SegmentType::Instructions}; - NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; + NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress}; auto module0 = std::make_unique(device, nullptr, ModuleType::User); module0->symbols[incorrectDevSymbolName] = relocatedSymbol; @@ -2825,7 +2825,7 @@ TEST_F(ModuleTests, whenCopyingPatchedSegmentsThenAllocationsAreSetWritableForTb linkerInput->traits.requiresPatchingOfInstructionSegments = true; pModule->translationUnit->programInfo.linkerInput = std::move(linkerInput); - NEO::Linker::PatchableSegments segments{{data, 1}}; + NEO::Linker::PatchableSegments segments{{data, 0u, 1, std::string{}}}; auto allocation = pModule->kernelImmDatas[0]->getIsaGraphicsAllocation(); diff --git a/opencl/source/program/process_device_binary.cpp b/opencl/source/program/process_device_binary.cpp index ebd28358f0..580918cbc0 100644 --- a/opencl/source/program/process_device_binary.cpp +++ b/opencl/source/program/process_device_binary.cpp @@ -100,7 +100,8 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const auto &kernHeapInfo = kernelInfo->heapInfo; const char *originalIsa = reinterpret_cast(kernHeapInfo.pKernelHeap); patchedIsaTempStorage.push_back(std::vector(originalIsa, originalIsa + kernHeapInfo.KernelHeapSize)); - isaSegmentsForPatching.push_back(Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), kernHeapInfo.KernelHeapSize}); + DEBUG_BREAK_IF(nullptr == kernelInfo->getGraphicsAllocation()); + isaSegmentsForPatching.push_back(Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), static_cast(kernelInfo->getGraphicsAllocation()->getGpuAddressToPatch()), kernHeapInfo.KernelHeapSize, kernelInfo->kernelDescriptor.kernelMetadata.kernelName}); kernelDescriptors.push_back(&kernelInfo->kernelDescriptor); } } @@ -123,9 +124,6 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const } else if (linkerInput->getTraits().requiresPatchingOfInstructionSegments) { for (auto kernelId = 0u; kernelId < kernelInfoArray.size(); kernelId++) { const auto &kernelInfo = kernelInfoArray[kernelId]; - if (nullptr == kernelInfo->getGraphicsAllocation()) { - continue; - } auto &kernHeapInfo = kernelInfo->heapInfo; auto segmentId = &kernelInfo - &kernelInfoArray[0]; auto &hwInfo = pDevice->getHardwareInfo(); diff --git a/opencl/test/unit_test/program/kernel_data.cpp b/opencl/test/unit_test/program/kernel_data.cpp index 51970a7b27..9d720a12d4 100644 --- a/opencl/test/unit_test/program/kernel_data.cpp +++ b/opencl/test/unit_test/program/kernel_data.cpp @@ -1319,6 +1319,9 @@ TEST_F(KernelDataTest, givenRelocationTablePatchTokenThenLinkerInputIsCreated) { token.Token = PATCH_TOKEN_PROGRAM_RELOCATION_TABLE; token.Size = static_cast(sizeof(SPatchFunctionTableInfo)); token.NumEntries = 0; + kernelHeapSize = 0x100; //force creating kernel allocation for ISA + auto kernelHeapData = std::make_unique(kernelHeapSize); + pKernelHeap = kernelHeapData.get(); pPatchList = &token; patchListSize = token.Size; diff --git a/opencl/test/unit_test/program/program_data_tests.cpp b/opencl/test/unit_test/program/program_data_tests.cpp index 4340c5ecc5..08a5324e3a 100644 --- a/opencl/test/unit_test/program/program_data_tests.cpp +++ b/opencl/test/unit_test/program/program_data_tests.cpp @@ -586,6 +586,7 @@ TEST(ProgramLinkBinaryTest, whenLinkerUnresolvedExternalThenLinkFailedAndBuildLo kernelHeap.resize(32, 7); kernelInfo.heapInfo.pKernelHeap = kernelHeap.data(); kernelInfo.heapInfo.KernelHeapSize = static_cast(kernelHeap.size()); + kernelInfo.createKernelAllocation(device->getDevice(), false); program.getKernelInfoArray(rootDeviceIndex).push_back(&kernelInfo); program.setLinkerInput(rootDeviceIndex, std::move(linkerInput)); @@ -600,6 +601,7 @@ TEST(ProgramLinkBinaryTest, whenLinkerUnresolvedExternalThenLinkFailedAndBuildLo expectedUnresolvedExternals.push_back(Linker::UnresolvedExternal{relocation, 0, false}); auto expectedError = constructLinkerErrorMessage(expectedUnresolvedExternals, std::vector{"kernel : " + kernelInfo.kernelDescriptor.kernelMetadata.kernelName}); EXPECT_TRUE(hasSubstr(buildLog, expectedError)); + device->getMemoryManager()->freeGraphicsMemory(kernelInfo.getGraphicsAllocation()); } TEST_F(ProgramDataTest, whenLinkerInputValidThenIsaIsProperlyPatched) { diff --git a/shared/source/compiler_interface/linker.cpp b/shared/source/compiler_interface/linker.cpp index 166c26d29f..3680f646cd 100644 --- a/shared/source/compiler_interface/linker.cpp +++ b/shared/source/compiler_interface/linker.cpp @@ -203,6 +203,14 @@ void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf } break; } symbols.insert({elf.getSymbolName(symbol.name), symbolInfo}); + } else if (type == Elf::SYMBOL_TABLE_TYPE::STT_FUNC) { + DEBUG_BREAK_IF(Elf::SYMBOL_TABLE_BIND::STB_LOCAL != bind); + LocalFuncSymbolInfo localSymbolInfo; + localSymbolInfo.offset = static_cast(symbol.value); + localSymbolInfo.size = static_cast(symbol.size); + auto symbolSectionName = elf.getSectionName(symbol.shndx); + localSymbolInfo.targetedKernelSectionName = symbolSectionName.substr(Elf::SectionsNamesZebin::textPrefix.length()); + localSymbols.insert({elf.getSymbolName(symbol.name), localSymbolInfo}); } } @@ -267,7 +275,8 @@ void LinkerInput::parseRelocationForExtFuncUsage(const RelocationInfo &relocInfo } } -bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings) { +bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings, + const PatchableSegments &instructionsSegments) { relocatedSymbols.reserve(data.getSymbols().size()); for (auto &symbol : data.getSymbols()) { const SegmentInfo *seg = nullptr; @@ -295,6 +304,15 @@ bool Linker::processRelocations(const SegmentInfo &globalVariables, const Segmen } relocatedSymbols[symbol.first] = {symbol.second, gpuAddress}; } + localRelocatedSymbols.reserve(data.getLocalSymbols().size()); + for (auto &localSymbol : data.getLocalSymbols()) { + for (auto &s : instructionsSegments) { + if (s.kernelName == localSymbol.second.targetedKernelSectionName) { + uintptr_t gpuAddress = s.gpuAddress + localSymbol.second.offset; + localRelocatedSymbols[localSymbol.first] = {localSymbol.second, gpuAddress}; + } + } + } return true; } @@ -347,6 +365,20 @@ void Linker::patchInstructionsSegments(const std::vector &inst continue; } auto symbolIt = relocatedSymbols.find(relocation.symbolName); + if (symbolIt == relocatedSymbols.end()) { + auto localSymbolIt = localRelocatedSymbols.find(relocation.symbolName); + if (localRelocatedSymbols.end() != localSymbolIt) { + if (localSymbolIt->first == kernelDescriptors[segId]->kernelMetadata.kernelName) { + uint64_t patchValue = localSymbolIt->second.gpuAddress + relocation.addend; + patchAddress(relocAddress, patchValue, relocation); + continue; + } + } else if (relocation.symbolName.empty()) { + uint64_t patchValue = 0; + patchAddress(relocAddress, patchValue, relocation); + continue; + } + } bool unresolvedExternal = (symbolIt == relocatedSymbols.end()); if (invalidOffset || unresolvedExternal) { uint32_t segId = static_cast(segIt - instructionsSegments.begin()); @@ -536,7 +568,7 @@ void Linker::resolveBuiltins(Device *pDevice, UnresolvedExternals &outUnresolved int vecIndex = static_cast(outUnresolvedExternals.size() - 1u); for (; vecIndex >= 0; --vecIndex) { if (outUnresolvedExternals[vecIndex].unresolvedRelocation.symbolName == subDeviceID) { - RelocatedSymbol symbol; + RelocatedSymbol symbol; symbol.gpuAddress = static_cast(pDevice->getDefaultEngine().commandStreamReceiver->getWorkPartitionAllocationGpuAddress()); auto relocAddress = ptrOffset(instructionsSegments[outUnresolvedExternals[vecIndex].instructionsSegmentId].hostPointer, static_cast(outUnresolvedExternals[vecIndex].unresolvedRelocation.offset)); diff --git a/shared/source/compiler_interface/linker.h b/shared/source/compiler_interface/linker.h index cfd80c0163..b0b1bda39f 100644 --- a/shared/source/compiler_interface/linker.h +++ b/shared/source/compiler_interface/linker.h @@ -55,6 +55,12 @@ struct SymbolInfo { SegmentType segment = SegmentType::Unknown; }; +struct LocalFuncSymbolInfo { + uint32_t offset = std::numeric_limits::max(); + uint32_t size = std::numeric_limits::max(); + std::string targetedKernelSectionName; +}; + struct LinkerInput { union Traits { enum PointerSize : uint8_t { @@ -97,6 +103,7 @@ struct LinkerInput { using SectionNameToSegmentIdMap = std::unordered_map; using Relocations = std::vector; using SymbolMap = std::unordered_map; + using LocalSymbolMap = std::unordered_map; using RelocationsPerInstSegment = std::vector; virtual ~LinkerInput() = default; @@ -123,6 +130,10 @@ struct LinkerInput { return symbols; } + const LocalSymbolMap &getLocalSymbols() const { + return localSymbols; + } + void addSymbol(const std::string &symbolName, const SymbolInfo &symbolInfo) { symbols.emplace(std::make_pair(symbolName, symbolInfo)); } @@ -156,6 +167,7 @@ struct LinkerInput { Traits traits; SymbolMap symbols; + LocalSymbolMap localSymbols; RelocationsPerInstSegment textRelocations; Relocations dataRelocations; std::vector> extFuncSymbols; @@ -177,7 +189,9 @@ struct Linker { struct PatchableSegment { void *hostPointer = nullptr; + uintptr_t gpuAddress = 0; size_t segmentSize = std::numeric_limits::max(); + std::string kernelName; }; struct UnresolvedExternal { @@ -186,12 +200,14 @@ struct Linker { bool internalError = false; }; + template struct RelocatedSymbol { - SymbolInfo symbol; + T symbol; uintptr_t gpuAddress = std::numeric_limits::max(); }; - using RelocatedSymbolsMap = std::unordered_map; + using RelocatedSymbolsMap = std::unordered_map>; + using LocalsRelocatedSymbolsMap = std::unordered_map>; using PatchableSegments = std::vector; using UnresolvedExternals = std::vector; using KernelDescriptorsT = std::vector; @@ -207,7 +223,7 @@ struct Linker { const KernelDescriptorsT &kernelDescriptors, ExternalFunctionsT &externalFunctions) { bool success = data.isValid(); auto initialUnresolvedExternalsCount = outUnresolvedExternals.size(); - success = success && processRelocations(globalVariablesSegInfo, globalConstantsSegInfo, exportedFunctionsSegInfo, globalStringsSegInfo); + success = success && processRelocations(globalVariablesSegInfo, globalConstantsSegInfo, exportedFunctionsSegInfo, globalStringsSegInfo, instructionsSegments); if (!success) { return LinkingStatus::Error; } @@ -238,8 +254,9 @@ struct Linker { protected: const LinkerInput &data; RelocatedSymbolsMap relocatedSymbols; + LocalsRelocatedSymbolsMap localRelocatedSymbols; - bool processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings); + bool processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings, const PatchableSegments &instructionsSegments); void patchInstructionsSegments(const std::vector &instructionsSegments, std::vector &outUnresolvedExternals, const KernelDescriptorsT &kernelDescriptors); diff --git a/shared/test/common/compiler_interface/linker_mock.h b/shared/test/common/compiler_interface/linker_mock.h index f5c534360a..ef521ad7e1 100644 --- a/shared/test/common/compiler_interface/linker_mock.h +++ b/shared/test/common/compiler_interface/linker_mock.h @@ -27,6 +27,7 @@ struct WhiteBox : NEO::LinkerInput { using BaseClass::extFuncSymbols; using BaseClass::extFunDependencies; using BaseClass::kernelDependencies; + using BaseClass::localSymbols; using BaseClass::parseRelocationForExtFuncUsage; using BaseClass::symbols; using BaseClass::textRelocations; @@ -38,8 +39,10 @@ template <> struct WhiteBox : NEO::Linker { using BaseClass = NEO::Linker; using BaseClass::BaseClass; + using BaseClass::localRelocatedSymbols; using BaseClass::patchDataSegments; using BaseClass::patchInstructionsSegments; + using BaseClass::processRelocations; using BaseClass::relocatedSymbols; using BaseClass::resolveExternalFunctions; }; diff --git a/shared/test/unit_test/compiler_interface/linker_tests.cpp b/shared/test/unit_test/compiler_interface/linker_tests.cpp index b45c491a42..1bade069d3 100644 --- a/shared/test/unit_test/compiler_interface/linker_tests.cpp +++ b/shared/test/unit_test/compiler_interface/linker_tests.cpp @@ -2518,4 +2518,184 @@ TEST(LinkerTests, givenPerThreadPayloadOffsetRelocationWhenPatchingInstructionSe linker.patchInstructionsSegments({segmentToPatch}, unresolvedExternals, kernelDescriptors); auto perThreadPayloadOffsetPatchedValue = reinterpret_cast(ptrOffset(segmentToPatch.hostPointer, static_cast(rel.offset))); EXPECT_EQ(kd.kernelAttributes.crossThreadDataSize, static_cast(*perThreadPayloadOffsetPatchedValue)); -} \ No newline at end of file +} + +TEST(LinkerTests, givenRelocationToInstructionSegmentWithLocalSymbolPointingToSameSegmentThenItIsPatched) { + std::string kernelName{"test_kernel"}; + WhiteBox linkerInput; + linkerInput.traits.requiresPatchingOfInstructionSegments = true; + NEO::LinkerInput::RelocationInfo rela; + rela.offset = 0U; + rela.addend = 128U; + rela.type = NEO::LinkerInput::RelocationInfo::Type::Address; + rela.symbolName = kernelName; + rela.relocationSegment = NEO::SegmentType::Instructions; + linkerInput.textRelocations.push_back({rela}); + + WhiteBox linker(linkerInput); + constexpr uint64_t symValue = 64U; + linker.localRelocatedSymbols[kernelName].gpuAddress = symValue; + + uint64_t instructionSegmentData{std::numeric_limits::max()}; + NEO::Linker::PatchableSegment instructionSegmentToPatch; + instructionSegmentToPatch.hostPointer = reinterpret_cast(&instructionSegmentData); + instructionSegmentToPatch.segmentSize = sizeof(instructionSegmentData); + + NEO::Linker::UnresolvedExternals unresolvedExternals; + ASSERT_EQ(0u, unresolvedExternals.size()); + NEO::Linker::KernelDescriptorsT kernelDescriptors; + + KernelDescriptor kd; + kd.kernelMetadata.kernelName = kernelName; + kernelDescriptors.push_back(&kd); + linker.patchInstructionsSegments({instructionSegmentToPatch}, unresolvedExternals, kernelDescriptors); + auto instructionSegmentPatchedData = reinterpret_cast(ptrOffset(instructionSegmentToPatch.hostPointer, static_cast(rela.offset))); + EXPECT_EQ(symValue + rela.addend, static_cast(*instructionSegmentPatchedData)); + EXPECT_EQ(0u, unresolvedExternals.size()); +} + +TEST(LinkerTests, givenRelocationToInstructionSegmentWithLocalSymbolPointingToDifferentSegmentThenItIsNotPatched) { + std::string kernelName{"test_kernel"}; + WhiteBox linkerInput; + linkerInput.traits.requiresPatchingOfInstructionSegments = true; + NEO::LinkerInput::RelocationInfo rela; + rela.offset = 0U; + rela.addend = 128U; + rela.type = NEO::LinkerInput::RelocationInfo::Type::Address; + rela.symbolName = kernelName; + rela.relocationSegment = NEO::SegmentType::Instructions; + linkerInput.textRelocations.push_back({rela}); + + WhiteBox linker(linkerInput); + constexpr uint64_t symValue = 64U; + linker.localRelocatedSymbols[kernelName].gpuAddress = symValue; + + uint64_t instructionSegmentData{std::numeric_limits::max()}; + NEO::Linker::PatchableSegment instructionSegmentToPatch; + instructionSegmentToPatch.hostPointer = reinterpret_cast(&instructionSegmentData); + instructionSegmentToPatch.segmentSize = sizeof(instructionSegmentData); + + NEO::Linker::UnresolvedExternals unresolvedExternals; + ASSERT_EQ(0u, unresolvedExternals.size()); + NEO::Linker::KernelDescriptorsT kernelDescriptors; + + KernelDescriptor kd; + kd.kernelMetadata.kernelName = "not_matching"; + kernelDescriptors.push_back(&kd); + linker.patchInstructionsSegments({instructionSegmentToPatch}, unresolvedExternals, kernelDescriptors); + auto instructionSegmentPatchedData = reinterpret_cast(ptrOffset(instructionSegmentToPatch.hostPointer, static_cast(rela.offset))); + EXPECT_EQ(std::numeric_limits::max(), static_cast(*instructionSegmentPatchedData)); + EXPECT_EQ(1u, unresolvedExternals.size()); +} + +TEST(LinkerTests, givenRelocationToInstructionSegmentWithLocalUndefinedSymbolThenItIsPatchedWithZeroes) { + WhiteBox linkerInput; + linkerInput.traits.requiresPatchingOfInstructionSegments = true; + NEO::LinkerInput::RelocationInfo rela; + rela.offset = 0U; + rela.addend = 128U; + rela.type = NEO::LinkerInput::RelocationInfo::Type::Address; + rela.symbolName = ""; + rela.relocationSegment = NEO::SegmentType::Instructions; + linkerInput.textRelocations.push_back({rela}); + + WhiteBox linker(linkerInput); + EXPECT_TRUE(linker.relocatedSymbols.empty()); + EXPECT_TRUE(linker.localRelocatedSymbols.empty()); + + uint64_t instructionSegmentData{std::numeric_limits::max()}; + NEO::Linker::PatchableSegment instructionSegmentToPatch; + instructionSegmentToPatch.hostPointer = reinterpret_cast(&instructionSegmentData); + instructionSegmentToPatch.segmentSize = sizeof(instructionSegmentData); + + NEO::Linker::UnresolvedExternals unresolvedExternals; + ASSERT_EQ(0u, unresolvedExternals.size()); + NEO::Linker::KernelDescriptorsT kernelDescriptors; + + linker.patchInstructionsSegments({instructionSegmentToPatch}, unresolvedExternals, kernelDescriptors); + auto instructionSegmentPatchedData = reinterpret_cast(ptrOffset(instructionSegmentToPatch.hostPointer, static_cast(rela.offset))); + EXPECT_EQ(0u, static_cast(*instructionSegmentPatchedData)); + EXPECT_EQ(0u, unresolvedExternals.size()); +} + +TEST(LinkerTests, givenElfWithLocalSymbolsWhenDecodingElfSymbolTableAndRelocationsThenOnlySymbolsWithTypeFunctionArePopulated) { + NEO::LinkerInput linkerInput = {}; + NEO::Elf::ElfFileHeader header; + MockElf elf64; + elf64.elfFileHeader = &header; + + std::unordered_map sectionNames; + std::string kernelName = "test_kernel"; + sectionNames[0] = NEO::Elf::SectionsNamesZebin::textPrefix.str() + kernelName; + elf64.setupSecionNames(std::move(sectionNames)); + elf64.overrideSymbolName = true; + + elf64.symbolTable.reserve(2); + auto &localFuncSymbol = elf64.symbolTable.emplace_back(); + localFuncSymbol.setBinding(NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL); + localFuncSymbol.setType(NEO::Elf::SYMBOL_TABLE_TYPE::STT_FUNC); + localFuncSymbol.name = 0x20; + localFuncSymbol.other = 0; + localFuncSymbol.shndx = 0; + localFuncSymbol.size = 0x8; + localFuncSymbol.value = 0x4000; + + auto &localIgnoredSymbol = elf64.symbolTable.emplace_back(); + localIgnoredSymbol.setBinding(NEO::Elf::SYMBOL_TABLE_BIND::STB_LOCAL); + localIgnoredSymbol.setType(NEO::Elf::SYMBOL_TABLE_TYPE::STT_OBJECT); + localIgnoredSymbol.name = std::numeric_limits::max(); + localIgnoredSymbol.other = std::numeric_limits::max(); + localIgnoredSymbol.shndx = std::numeric_limits::max(); + localIgnoredSymbol.size = std::numeric_limits::max(); + localIgnoredSymbol.value = std::numeric_limits::max(); + + NEO::LinkerInput::SectionNameToSegmentIdMap nameToKernelId; + linkerInput.decodeElfSymbolTableAndRelocations(elf64, nameToKernelId); + + const auto &symbols = linkerInput.getSymbols(); + EXPECT_EQ(0u, symbols.size()); + + const auto &localSymbols = linkerInput.getLocalSymbols(); + EXPECT_EQ(1u, localSymbols.size()); + + const auto &retrievedSymbol = localSymbols.at(std::to_string(localFuncSymbol.name)); + EXPECT_EQ(retrievedSymbol.offset, localFuncSymbol.value); + EXPECT_EQ(retrievedSymbol.size, localFuncSymbol.size); + EXPECT_STREQ(retrievedSymbol.targetedKernelSectionName.c_str(), kernelName.c_str()); +} + +TEST(LinkerTest, givenLocalFuncSymbolsWhenProcessingRelocationsThenLocalSymbolsAreRelocated) { + std::string kernelName{"test_kernel"}; + WhiteBox linkerInput; + + LocalFuncSymbolInfo localSymInfo; + localSymInfo.offset = 0x20; + localSymInfo.size = 0x30; + localSymInfo.targetedKernelSectionName = kernelName; + + LocalFuncSymbolInfo ignoredSymInfo; + ignoredSymInfo.offset = 0x40; + ignoredSymInfo.size = 0x50; + ignoredSymInfo.targetedKernelSectionName = "mismatched_kernel"; + + linkerInput.localSymbols[localSymInfo.targetedKernelSectionName] = localSymInfo; + linkerInput.localSymbols[ignoredSymInfo.targetedKernelSectionName] = ignoredSymInfo; + + WhiteBox linker(linkerInput); + const NEO::Linker::SegmentInfo gVariables{}, gConstants{}, expFuncs{}, gStrings{}; + NEO::Linker::PatchableSegments insSegments; + insSegments.reserve(2); + auto &emplacedTargeted = insSegments.emplace_back(); + emplacedTargeted.gpuAddress = 0x1000; + emplacedTargeted.kernelName = kernelName; + + auto &emplacedOther = insSegments.emplace_back(); + emplacedOther.gpuAddress = 0x2000; + emplacedOther.kernelName = "other_kernel"; + + auto res = linker.processRelocations(gVariables, gConstants, expFuncs, gStrings, insSegments); + EXPECT_TRUE(res); + EXPECT_EQ(1u, linker.localRelocatedSymbols.size()); + const auto &localRelocatedSymbolInfo = linker.localRelocatedSymbols.at(kernelName); + EXPECT_EQ(emplacedTargeted.gpuAddress + localSymInfo.offset, localRelocatedSymbolInfo.gpuAddress); +}