mirror of
https://github.com/intel/compute-runtime.git
synced 2025-09-15 13:01:45 +08:00
Linker: add support for symbols with local binding
This commits add support for relocating symbols with local binding and of functional type (STB_LOCAL, STT_FUNC). Related-To: NEO-7299 Signed-off-by: Kacper Nowak <kacper.nowak@intel.com>
This commit is contained in:

committed by
Compute-Runtime-Automation

parent
824c781ab5
commit
710c8cf5ef
@ -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<const char *>(kernHeapInfo.pKernelHeap);
|
||||
patchedIsaTempStorage.push_back(std::vector<char>(originalIsa, originalIsa + kernHeapInfo.KernelHeapSize));
|
||||
isaSegmentsForPatching.push_back(Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), kernHeapInfo.KernelHeapSize});
|
||||
isaSegmentsForPatching.push_back(Linker::PatchableSegment{patchedIsaTempStorage.rbegin()->data(), static_cast<uintptr_t>(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<const char *>(kernHeapInfo.pKernelHeap);
|
||||
patchedIsaTempStorage.push_back(std::vector<char>(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<uintptr_t>(kernelImmDatas.at(i)->getIsaGraphicsAllocation()->getGpuAddressToPatch()), kernHeapInfo.KernelHeapSize, kernelInfo->kernelDescriptor.kernelMetadata.kernelName});
|
||||
}
|
||||
}
|
||||
for (const auto &unresolvedExternal : moduleId->unresolvedExternalsInfo) {
|
||||
|
@ -994,7 +994,7 @@ HWTEST_F(NotifyModuleLoadTest, givenDebuggingEnabledWhenModuleWithUnresolvedSymb
|
||||
}
|
||||
|
||||
NEO::SymbolInfo symbolInfo{};
|
||||
NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress};
|
||||
NEO::Linker::RelocatedSymbol<SymbolInfo> relocatedSymbol{symbolInfo, gpuAddress};
|
||||
|
||||
auto module1 = std::make_unique<Module>(device, nullptr, ModuleType::User);
|
||||
|
||||
|
@ -1212,7 +1212,7 @@ TEST_F(ModuleDynamicLinkTests, givenModuleWithUnresolvedSymbolWhenTheOtherModule
|
||||
unresolvedExternal.unresolvedRelocation = unresolvedRelocation;
|
||||
|
||||
NEO::SymbolInfo symbolInfo{};
|
||||
NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> 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<NEO::SymbolInfo> 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<NEO::SymbolInfo> module0RelocatedSymbol{module0SymbolInfo, gpuAddress0};
|
||||
|
||||
NEO::SymbolInfo module1SymbolInfo{};
|
||||
NEO::Linker::RelocatedSymbol module1RelocatedSymbol{module1SymbolInfo, gpuAddress1};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> module1RelocatedSymbol{module1SymbolInfo, gpuAddress1};
|
||||
|
||||
NEO::SymbolInfo module2SymbolInfo{};
|
||||
NEO::Linker::RelocatedSymbol module2RelocatedSymbol{module2SymbolInfo, gpuAddress2};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> 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<NEO::SymbolInfo> module0RelocatedSymbol{module0SymbolInfo, gpuAddress0};
|
||||
|
||||
NEO::SymbolInfo module1SymbolInfo{};
|
||||
NEO::Linker::RelocatedSymbol module1RelocatedSymbol{module1SymbolInfo, gpuAddress1};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> module1RelocatedSymbol{module1SymbolInfo, gpuAddress1};
|
||||
|
||||
NEO::SymbolInfo module2SymbolInfo{};
|
||||
NEO::Linker::RelocatedSymbol module2RelocatedSymbol{module2SymbolInfo, gpuAddress2};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> 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<NEO::SymbolInfo> relocatedSymbol{symbolInfo, gpuAddress};
|
||||
|
||||
NEO::SymbolInfo symbolInfo2{};
|
||||
NEO::Linker::RelocatedSymbol relocatedSymbol2{symbolInfo2, gpuAddress};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> 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<NEO::SymbolInfo> 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<NEO::SymbolInfo> 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<NEO::SymbolInfo> 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<NEO::SymbolInfo> relocatedSymbol{symbolInfo, gpuAddress};
|
||||
|
||||
auto module0 = std::make_unique<Module>(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<NEO::SymbolInfo> relocatedSymbol{symbolInfo, gpuAddress};
|
||||
|
||||
auto module0 = std::make_unique<Module>(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<uint32_t>(symbolsSize), SegmentType::GlobalVariables};
|
||||
NEO::Linker::RelocatedSymbol globalVariablesRelocatedSymbol{globalVariablesSymbolInfo, globalVarGpuAddress};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> globalVariablesRelocatedSymbol{globalVariablesSymbolInfo, globalVarGpuAddress};
|
||||
|
||||
uint64_t globalConstGpuAddress = 0x12347000;
|
||||
NEO::SymbolInfo globalConstantsSymbolInfo{0, static_cast<uint32_t>(symbolsSize), SegmentType::GlobalConstants};
|
||||
NEO::Linker::RelocatedSymbol globalConstansRelocatedSymbol{globalConstantsSymbolInfo, globalConstGpuAddress};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> globalConstansRelocatedSymbol{globalConstantsSymbolInfo, globalConstGpuAddress};
|
||||
|
||||
auto module0 = std::make_unique<MockModule>(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<uint32_t>(symbolSize), SegmentType::Instructions};
|
||||
NEO::Linker::RelocatedSymbol relocatedSymbol{symbolInfo, gpuAddress};
|
||||
NEO::Linker::RelocatedSymbol<NEO::SymbolInfo> relocatedSymbol{symbolInfo, gpuAddress};
|
||||
|
||||
auto module0 = std::make_unique<MockModule>(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();
|
||||
|
||||
|
@ -100,7 +100,8 @@ cl_int Program::linkBinary(Device *pDevice, const void *constantsInitData, const
|
||||
auto &kernHeapInfo = kernelInfo->heapInfo;
|
||||
const char *originalIsa = reinterpret_cast<const char *>(kernHeapInfo.pKernelHeap);
|
||||
patchedIsaTempStorage.push_back(std::vector<char>(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<uintptr_t>(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();
|
||||
|
@ -1319,6 +1319,9 @@ TEST_F(KernelDataTest, givenRelocationTablePatchTokenThenLinkerInputIsCreated) {
|
||||
token.Token = PATCH_TOKEN_PROGRAM_RELOCATION_TABLE;
|
||||
token.Size = static_cast<uint32_t>(sizeof(SPatchFunctionTableInfo));
|
||||
token.NumEntries = 0;
|
||||
kernelHeapSize = 0x100; //force creating kernel allocation for ISA
|
||||
auto kernelHeapData = std::make_unique<char[]>(kernelHeapSize);
|
||||
pKernelHeap = kernelHeapData.get();
|
||||
|
||||
pPatchList = &token;
|
||||
patchListSize = token.Size;
|
||||
|
@ -586,6 +586,7 @@ TEST(ProgramLinkBinaryTest, whenLinkerUnresolvedExternalThenLinkFailedAndBuildLo
|
||||
kernelHeap.resize(32, 7);
|
||||
kernelInfo.heapInfo.pKernelHeap = kernelHeap.data();
|
||||
kernelInfo.heapInfo.KernelHeapSize = static_cast<uint32_t>(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<std::string>{"kernel : " + kernelInfo.kernelDescriptor.kernelMetadata.kernelName});
|
||||
EXPECT_TRUE(hasSubstr(buildLog, expectedError));
|
||||
device->getMemoryManager()->freeGraphicsMemory(kernelInfo.getGraphicsAllocation());
|
||||
}
|
||||
|
||||
TEST_F(ProgramDataTest, whenLinkerInputValidThenIsaIsProperlyPatched) {
|
||||
|
@ -203,6 +203,14 @@ void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64>
|
||||
} 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<uint32_t>(symbol.value);
|
||||
localSymbolInfo.size = static_cast<uint32_t>(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<PatchableSegment> &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<uint32_t>(segIt - instructionsSegments.begin());
|
||||
@ -536,7 +568,7 @@ void Linker::resolveBuiltins(Device *pDevice, UnresolvedExternals &outUnresolved
|
||||
int vecIndex = static_cast<int>(outUnresolvedExternals.size() - 1u);
|
||||
for (; vecIndex >= 0; --vecIndex) {
|
||||
if (outUnresolvedExternals[vecIndex].unresolvedRelocation.symbolName == subDeviceID) {
|
||||
RelocatedSymbol symbol;
|
||||
RelocatedSymbol<SymbolInfo> symbol;
|
||||
symbol.gpuAddress = static_cast<uintptr_t>(pDevice->getDefaultEngine().commandStreamReceiver->getWorkPartitionAllocationGpuAddress());
|
||||
auto relocAddress = ptrOffset(instructionsSegments[outUnresolvedExternals[vecIndex].instructionsSegmentId].hostPointer,
|
||||
static_cast<uintptr_t>(outUnresolvedExternals[vecIndex].unresolvedRelocation.offset));
|
||||
|
@ -55,6 +55,12 @@ struct SymbolInfo {
|
||||
SegmentType segment = SegmentType::Unknown;
|
||||
};
|
||||
|
||||
struct LocalFuncSymbolInfo {
|
||||
uint32_t offset = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t size = std::numeric_limits<uint32_t>::max();
|
||||
std::string targetedKernelSectionName;
|
||||
};
|
||||
|
||||
struct LinkerInput {
|
||||
union Traits {
|
||||
enum PointerSize : uint8_t {
|
||||
@ -97,6 +103,7 @@ struct LinkerInput {
|
||||
using SectionNameToSegmentIdMap = std::unordered_map<std::string, uint32_t>;
|
||||
using Relocations = std::vector<RelocationInfo>;
|
||||
using SymbolMap = std::unordered_map<std::string, SymbolInfo>;
|
||||
using LocalSymbolMap = std::unordered_map<std::string, LocalFuncSymbolInfo>;
|
||||
using RelocationsPerInstSegment = std::vector<Relocations>;
|
||||
|
||||
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<std::pair<std::string, SymbolInfo>> extFuncSymbols;
|
||||
@ -177,7 +189,9 @@ struct Linker {
|
||||
|
||||
struct PatchableSegment {
|
||||
void *hostPointer = nullptr;
|
||||
uintptr_t gpuAddress = 0;
|
||||
size_t segmentSize = std::numeric_limits<size_t>::max();
|
||||
std::string kernelName;
|
||||
};
|
||||
|
||||
struct UnresolvedExternal {
|
||||
@ -186,12 +200,14 @@ struct Linker {
|
||||
bool internalError = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct RelocatedSymbol {
|
||||
SymbolInfo symbol;
|
||||
T symbol;
|
||||
uintptr_t gpuAddress = std::numeric_limits<uintptr_t>::max();
|
||||
};
|
||||
|
||||
using RelocatedSymbolsMap = std::unordered_map<std::string, RelocatedSymbol>;
|
||||
using RelocatedSymbolsMap = std::unordered_map<std::string, RelocatedSymbol<SymbolInfo>>;
|
||||
using LocalsRelocatedSymbolsMap = std::unordered_map<std::string, RelocatedSymbol<LocalFuncSymbolInfo>>;
|
||||
using PatchableSegments = std::vector<PatchableSegment>;
|
||||
using UnresolvedExternals = std::vector<UnresolvedExternal>;
|
||||
using KernelDescriptorsT = std::vector<KernelDescriptor *>;
|
||||
@ -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<PatchableSegment> &instructionsSegments, std::vector<UnresolvedExternal> &outUnresolvedExternals, const KernelDescriptorsT &kernelDescriptors);
|
||||
|
||||
|
@ -27,6 +27,7 @@ struct WhiteBox<NEO::LinkerInput> : 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> : 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;
|
||||
};
|
||||
|
@ -2519,3 +2519,183 @@ TEST(LinkerTests, givenPerThreadPayloadOffsetRelocationWhenPatchingInstructionSe
|
||||
auto perThreadPayloadOffsetPatchedValue = reinterpret_cast<uint32_t *>(ptrOffset(segmentToPatch.hostPointer, static_cast<size_t>(rel.offset)));
|
||||
EXPECT_EQ(kd.kernelAttributes.crossThreadDataSize, static_cast<uint32_t>(*perThreadPayloadOffsetPatchedValue));
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenRelocationToInstructionSegmentWithLocalSymbolPointingToSameSegmentThenItIsPatched) {
|
||||
std::string kernelName{"test_kernel"};
|
||||
WhiteBox<NEO::LinkerInput> 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<NEO::Linker> linker(linkerInput);
|
||||
constexpr uint64_t symValue = 64U;
|
||||
linker.localRelocatedSymbols[kernelName].gpuAddress = symValue;
|
||||
|
||||
uint64_t instructionSegmentData{std::numeric_limits<uint64_t>::max()};
|
||||
NEO::Linker::PatchableSegment instructionSegmentToPatch;
|
||||
instructionSegmentToPatch.hostPointer = reinterpret_cast<void *>(&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<uint64_t *>(ptrOffset(instructionSegmentToPatch.hostPointer, static_cast<size_t>(rela.offset)));
|
||||
EXPECT_EQ(symValue + rela.addend, static_cast<uint64_t>(*instructionSegmentPatchedData));
|
||||
EXPECT_EQ(0u, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenRelocationToInstructionSegmentWithLocalSymbolPointingToDifferentSegmentThenItIsNotPatched) {
|
||||
std::string kernelName{"test_kernel"};
|
||||
WhiteBox<NEO::LinkerInput> 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<NEO::Linker> linker(linkerInput);
|
||||
constexpr uint64_t symValue = 64U;
|
||||
linker.localRelocatedSymbols[kernelName].gpuAddress = symValue;
|
||||
|
||||
uint64_t instructionSegmentData{std::numeric_limits<uint64_t>::max()};
|
||||
NEO::Linker::PatchableSegment instructionSegmentToPatch;
|
||||
instructionSegmentToPatch.hostPointer = reinterpret_cast<void *>(&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<uint64_t *>(ptrOffset(instructionSegmentToPatch.hostPointer, static_cast<size_t>(rela.offset)));
|
||||
EXPECT_EQ(std::numeric_limits<uint64_t>::max(), static_cast<uint64_t>(*instructionSegmentPatchedData));
|
||||
EXPECT_EQ(1u, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenRelocationToInstructionSegmentWithLocalUndefinedSymbolThenItIsPatchedWithZeroes) {
|
||||
WhiteBox<NEO::LinkerInput> 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<NEO::Linker> linker(linkerInput);
|
||||
EXPECT_TRUE(linker.relocatedSymbols.empty());
|
||||
EXPECT_TRUE(linker.localRelocatedSymbols.empty());
|
||||
|
||||
uint64_t instructionSegmentData{std::numeric_limits<uint64_t>::max()};
|
||||
NEO::Linker::PatchableSegment instructionSegmentToPatch;
|
||||
instructionSegmentToPatch.hostPointer = reinterpret_cast<void *>(&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<uint64_t *>(ptrOffset(instructionSegmentToPatch.hostPointer, static_cast<size_t>(rela.offset)));
|
||||
EXPECT_EQ(0u, static_cast<uint64_t>(*instructionSegmentPatchedData));
|
||||
EXPECT_EQ(0u, unresolvedExternals.size());
|
||||
}
|
||||
|
||||
TEST(LinkerTests, givenElfWithLocalSymbolsWhenDecodingElfSymbolTableAndRelocationsThenOnlySymbolsWithTypeFunctionArePopulated) {
|
||||
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;
|
||||
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<uint32_t>::max();
|
||||
localIgnoredSymbol.other = std::numeric_limits<uint8_t>::max();
|
||||
localIgnoredSymbol.shndx = std::numeric_limits<uint16_t>::max();
|
||||
localIgnoredSymbol.size = std::numeric_limits<uint64_t>::max();
|
||||
localIgnoredSymbol.value = std::numeric_limits<uint64_t>::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<NEO::LinkerInput> 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<NEO::Linker> 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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user