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:
Kacper Nowak
2022-09-06 00:10:18 +00:00
committed by Compute-Runtime-Automation
parent 824c781ab5
commit 710c8cf5ef
10 changed files with 272 additions and 35 deletions

View File

@@ -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));

View File

@@ -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);