1 /*
2  * Copyright (C) 2019-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "shared/source/compiler_interface/linker.h"
9 
10 #include "shared/source/command_stream/command_stream_receiver.h"
11 #include "shared/source/compiler_interface/linker.inl"
12 #include "shared/source/device/device.h"
13 #include "shared/source/device_binary_format/elf/zebin_elf.h"
14 #include "shared/source/helpers/blit_commands_helper.h"
15 #include "shared/source/helpers/debug_helpers.h"
16 #include "shared/source/helpers/hw_helper.h"
17 #include "shared/source/helpers/ptr_math.h"
18 #include "shared/source/kernel/implicit_args.h"
19 #include "shared/source/kernel/kernel_descriptor.h"
20 #include "shared/source/memory_manager/graphics_allocation.h"
21 #include "shared/source/memory_manager/memory_manager.h"
22 
23 #include "RelocationInfo.h"
24 
25 #include <sstream>
26 
27 namespace NEO {
28 
getSegmentForSection(ConstStringRef name)29 SegmentType LinkerInput::getSegmentForSection(ConstStringRef name) {
30     if (name == NEO::Elf::SectionsNamesZebin::dataConst || name == NEO::Elf::SectionsNamesZebin::dataGlobalConst) {
31         return NEO::SegmentType::GlobalConstants;
32     } else if (name == NEO::Elf::SectionsNamesZebin::dataGlobal) {
33         return NEO::SegmentType::GlobalVariables;
34     } else if (name == NEO::Elf::SectionsNamesZebin::dataConstString) {
35         return NEO::SegmentType::GlobalStrings;
36     } else if (name.startsWith(NEO::Elf::SpecialSectionNames::text.data())) {
37         return NEO::SegmentType::Instructions;
38     }
39     return NEO::SegmentType::Unknown;
40 }
41 
decodeGlobalVariablesSymbolTable(const void * data,uint32_t numEntries)42 bool LinkerInput::decodeGlobalVariablesSymbolTable(const void *data, uint32_t numEntries) {
43     auto symbolEntryIt = reinterpret_cast<const vISA::GenSymEntry *>(data);
44     auto symbolEntryEnd = symbolEntryIt + numEntries;
45     symbols.reserve(symbols.size() + numEntries);
46     for (; symbolEntryIt != symbolEntryEnd; ++symbolEntryIt) {
47         DEBUG_BREAK_IF(symbols.count(symbolEntryIt->s_name) > 0);
48         SymbolInfo &symbolInfo = symbols[symbolEntryIt->s_name];
49         symbolInfo.offset = symbolEntryIt->s_offset;
50         symbolInfo.size = symbolEntryIt->s_size;
51         switch (symbolEntryIt->s_type) {
52         default:
53             DEBUG_BREAK_IF(true);
54             this->valid = false;
55             return false;
56         case vISA::S_GLOBAL_VAR:
57             symbolInfo.segment = SegmentType::GlobalVariables;
58             traits.exportsGlobalVariables = true;
59             break;
60         case vISA::S_GLOBAL_VAR_CONST:
61             symbolInfo.segment = SegmentType::GlobalConstants;
62             traits.exportsGlobalConstants = true;
63             break;
64         }
65     }
66     return true;
67 }
68 
decodeExportedFunctionsSymbolTable(const void * data,uint32_t numEntries,uint32_t instructionsSegmentId)69 bool LinkerInput::decodeExportedFunctionsSymbolTable(const void *data, uint32_t numEntries, uint32_t instructionsSegmentId) {
70     auto symbolEntryIt = reinterpret_cast<const vISA::GenSymEntry *>(data);
71     auto symbolEntryEnd = symbolEntryIt + numEntries;
72     symbols.reserve(symbols.size() + numEntries);
73     for (; symbolEntryIt != symbolEntryEnd; ++symbolEntryIt) {
74         SymbolInfo &symbolInfo = symbols[symbolEntryIt->s_name];
75         symbolInfo.offset = symbolEntryIt->s_offset;
76         symbolInfo.size = symbolEntryIt->s_size;
77         switch (symbolEntryIt->s_type) {
78         default:
79             DEBUG_BREAK_IF(true);
80             this->valid = false;
81             return false;
82         case vISA::S_UNDEF:
83             if (this->undefinedSymbolsAllowed) {
84                 symbols.erase(symbolEntryIt->s_name);
85                 break;
86             } else {
87                 DEBUG_BREAK_IF(true);
88                 this->valid = false;
89                 return false;
90             }
91         case vISA::S_GLOBAL_VAR:
92             symbolInfo.segment = SegmentType::GlobalVariables;
93             traits.exportsGlobalVariables = true;
94             break;
95         case vISA::S_GLOBAL_VAR_CONST:
96             symbolInfo.segment = SegmentType::GlobalConstants;
97             traits.exportsGlobalConstants = true;
98             break;
99         case vISA::S_FUNC:
100             symbolInfo.segment = SegmentType::Instructions;
101             traits.exportsFunctions = true;
102             UNRECOVERABLE_IF((this->exportedFunctionsSegmentId != -1) && (this->exportedFunctionsSegmentId != static_cast<int32_t>(instructionsSegmentId)));
103             this->exportedFunctionsSegmentId = static_cast<int32_t>(instructionsSegmentId);
104             break;
105         }
106     }
107     return true;
108 }
109 
decodeRelocationTable(const void * data,uint32_t numEntries,uint32_t instructionsSegmentId)110 bool LinkerInput::decodeRelocationTable(const void *data, uint32_t numEntries, uint32_t instructionsSegmentId) {
111     this->traits.requiresPatchingOfInstructionSegments = true;
112     auto relocEntryIt = reinterpret_cast<const vISA::GenRelocEntry *>(data);
113     auto relocEntryEnd = relocEntryIt + numEntries;
114     if (instructionsSegmentId >= relocations.size()) {
115         static_assert(std::is_nothrow_move_constructible<decltype(relocations[0])>::value, "");
116         relocations.resize(instructionsSegmentId + 1);
117     }
118 
119     auto &outRelocInfo = relocations[instructionsSegmentId];
120     outRelocInfo.reserve(numEntries);
121     for (; relocEntryIt != relocEntryEnd; ++relocEntryIt) {
122         RelocationInfo relocInfo{};
123         relocInfo.offset = relocEntryIt->r_offset;
124         relocInfo.symbolName = relocEntryIt->r_symbol;
125         relocInfo.relocationSegment = SegmentType::Instructions;
126         switch (relocEntryIt->r_type) {
127         default:
128             DEBUG_BREAK_IF(true);
129             this->valid = false;
130             return false;
131         case vISA::R_SYM_ADDR:
132             relocInfo.type = RelocationInfo::Type::Address;
133             break;
134         case vISA::R_SYM_ADDR_32:
135             relocInfo.type = RelocationInfo::Type::AddressLow;
136             break;
137         case vISA::R_SYM_ADDR_32_HI:
138             relocInfo.type = RelocationInfo::Type::AddressHigh;
139             break;
140         case vISA::R_PER_THREAD_PAYLOAD_OFFSET_32:
141             relocInfo.type = RelocationInfo::Type::PerThreadPayloadOffset;
142             break;
143         }
144         outRelocInfo.push_back(std::move(relocInfo));
145     }
146     return true;
147 }
148 
addDataRelocationInfo(const RelocationInfo & relocationInfo)149 void LinkerInput::addDataRelocationInfo(const RelocationInfo &relocationInfo) {
150     DEBUG_BREAK_IF((relocationInfo.relocationSegment != SegmentType::GlobalConstants) && (relocationInfo.relocationSegment != SegmentType::GlobalVariables));
151     this->traits.requiresPatchingOfGlobalVariablesBuffer |= (relocationInfo.relocationSegment == SegmentType::GlobalVariables);
152     this->traits.requiresPatchingOfGlobalConstantsBuffer |= (relocationInfo.relocationSegment == SegmentType::GlobalConstants);
153     this->dataRelocations.push_back(relocationInfo);
154 }
155 
addElfTextSegmentRelocation(RelocationInfo relocationInfo,uint32_t instructionsSegmentId)156 void LinkerInput::addElfTextSegmentRelocation(RelocationInfo relocationInfo, uint32_t instructionsSegmentId) {
157     this->traits.requiresPatchingOfInstructionSegments = true;
158 
159     if (instructionsSegmentId >= relocations.size()) {
160         static_assert(std::is_nothrow_move_constructible<decltype(relocations[0])>::value, "");
161         relocations.resize(instructionsSegmentId + 1);
162     }
163 
164     auto &outRelocInfo = relocations[instructionsSegmentId];
165 
166     relocationInfo.relocationSegment = SegmentType::Instructions;
167 
168     outRelocInfo.push_back(std::move(relocationInfo));
169 }
170 
decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64> & elf,const SectionNameToSegmentIdMap & nameToSegmentId)171 void LinkerInput::decodeElfSymbolTableAndRelocations(Elf::Elf<Elf::EI_CLASS_64> &elf, const SectionNameToSegmentIdMap &nameToSegmentId) {
172     for (auto &reloc : elf.getRelocations()) {
173         NEO::LinkerInput::RelocationInfo relocationInfo;
174         relocationInfo.offset = reloc.offset;
175         relocationInfo.symbolName = reloc.symbolName;
176 
177         switch (reloc.relocType) {
178         case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_64):
179             relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::Address;
180             break;
181         case uint32_t(Elf::RELOCATION_X8664_TYPE::R_X8664_32):
182             relocationInfo.type = NEO::LinkerInput::RelocationInfo::Type::AddressLow;
183             break;
184         default: // Zebin relocation type
185             relocationInfo.type = reloc.relocType < uint32_t(NEO::LinkerInput::RelocationInfo::Type::RelocTypeMax)
186                                       ? static_cast<NEO::LinkerInput::RelocationInfo::Type>(reloc.relocType)
187                                       : NEO::LinkerInput::RelocationInfo::Type::Unknown;
188             break;
189         }
190         auto name = elf.getSectionName(reloc.targetSectionIndex);
191         ConstStringRef nameRef(name);
192 
193         if (nameRef.startsWith(NEO::Elf::SectionsNamesZebin::textPrefix.data())) {
194             auto kernelName = name.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
195             auto segmentIdIter = nameToSegmentId.find(kernelName);
196             if (segmentIdIter != nameToSegmentId.end()) {
197                 this->addElfTextSegmentRelocation(relocationInfo, segmentIdIter->second);
198             }
199         } else if (nameRef.startsWith(NEO::Elf::SpecialSectionNames::data.data())) {
200             auto symbolSectionName = elf.getSectionName(reloc.symbolSectionIndex);
201             auto symbolSegment = getSegmentForSection(symbolSectionName);
202             auto relocationSegment = getSegmentForSection(nameRef);
203             if (symbolSegment != NEO::SegmentType::Unknown &&
204                 (relocationSegment == NEO::SegmentType::GlobalConstants || relocationSegment == NEO::SegmentType::GlobalVariables)) {
205                 relocationInfo.relocationSegment = relocationSegment;
206                 this->addDataRelocationInfo(relocationInfo);
207             }
208         }
209     }
210 
211     symbols.reserve(elf.getSymbols().size());
212 
213     for (auto &symbol : elf.getSymbols()) {
214         auto bind = elf.extractSymbolBind(symbol);
215 
216         if (bind == Elf::SYMBOL_TABLE_BIND::STB_GLOBAL) {
217             SymbolInfo symbolInfo;
218             symbolInfo.offset = static_cast<uint32_t>(symbol.value);
219             symbolInfo.size = static_cast<uint32_t>(symbol.size);
220             auto type = elf.extractSymbolType(symbol);
221 
222             auto symbolSectionName = elf.getSectionName(symbol.shndx);
223             auto symbolSegment = getSegmentForSection(symbolSectionName);
224 
225             switch (type) {
226             default:
227                 this->valid &= this->undefinedSymbolsAllowed;
228                 DEBUG_BREAK_IF(false == this->undefinedSymbolsAllowed);
229                 continue;
230             case Elf::SYMBOL_TABLE_TYPE::STT_OBJECT:
231                 symbolInfo.segment = symbolSegment;
232                 traits.exportsGlobalVariables |= symbolSegment == SegmentType::GlobalVariables;
233                 traits.exportsGlobalConstants |= symbolSegment == SegmentType::GlobalConstants;
234                 break;
235             case Elf::SYMBOL_TABLE_TYPE::STT_FUNC: {
236                 auto kernelName = symbolSectionName.substr(static_cast<int>(NEO::Elf::SectionsNamesZebin::textPrefix.length()));
237                 auto segmentIdIter = nameToSegmentId.find(kernelName);
238                 if (segmentIdIter != nameToSegmentId.end()) {
239                     symbolInfo.segment = SegmentType::Instructions;
240                     traits.exportsFunctions = true;
241                     int32_t instructionsSegmentId = static_cast<int32_t>(segmentIdIter->second);
242                     UNRECOVERABLE_IF((this->exportedFunctionsSegmentId != -1) && (this->exportedFunctionsSegmentId != instructionsSegmentId));
243                     this->exportedFunctionsSegmentId = instructionsSegmentId;
244                 }
245             } break;
246             }
247             symbols.insert({elf.getSymbolName(symbol.name), symbolInfo});
248         }
249     }
250 }
251 
processRelocations(const SegmentInfo & globalVariables,const SegmentInfo & globalConstants,const SegmentInfo & exportedFunctions,const SegmentInfo & globalStrings)252 bool Linker::processRelocations(const SegmentInfo &globalVariables, const SegmentInfo &globalConstants, const SegmentInfo &exportedFunctions, const SegmentInfo &globalStrings) {
253     relocatedSymbols.reserve(data.getSymbols().size());
254     for (auto &symbol : data.getSymbols()) {
255         const SegmentInfo *seg = nullptr;
256         switch (symbol.second.segment) {
257         default:
258             DEBUG_BREAK_IF(true);
259             return false;
260         case SegmentType::GlobalVariables:
261             seg = &globalVariables;
262             break;
263         case SegmentType::GlobalConstants:
264             seg = &globalConstants;
265             break;
266         case SegmentType::GlobalStrings:
267             seg = &globalStrings;
268             break;
269         case SegmentType::Instructions:
270             seg = &exportedFunctions;
271             break;
272         }
273         uintptr_t gpuAddress = seg->gpuAddress + symbol.second.offset;
274         if (symbol.second.offset + symbol.second.size > seg->segmentSize) {
275             DEBUG_BREAK_IF(true);
276             return false;
277         }
278         relocatedSymbols[symbol.first] = {symbol.second, gpuAddress};
279     }
280     return true;
281 }
282 
addressSizeInBytes(LinkerInput::RelocationInfo::Type relocationtype)283 uint32_t addressSizeInBytes(LinkerInput::RelocationInfo::Type relocationtype) {
284     return (relocationtype == LinkerInput::RelocationInfo::Type::Address) ? sizeof(uintptr_t) : sizeof(uint32_t);
285 }
286 
patchAddress(void * relocAddress,const Linker::RelocatedSymbol & symbol,const Linker::RelocationInfo & relocation)287 void Linker::patchAddress(void *relocAddress, const Linker::RelocatedSymbol &symbol, const Linker::RelocationInfo &relocation) {
288     uint64_t gpuAddressAs64bit = static_cast<uint64_t>(symbol.gpuAddress);
289     switch (relocation.type) {
290     default:
291         UNRECOVERABLE_IF(RelocationInfo::Type::Address != relocation.type);
292         *reinterpret_cast<uintptr_t *>(relocAddress) = symbol.gpuAddress;
293         break;
294     case RelocationInfo::Type::AddressLow:
295         *reinterpret_cast<uint32_t *>(relocAddress) = static_cast<uint32_t>(gpuAddressAs64bit & 0xffffffff);
296         break;
297     case RelocationInfo::Type::AddressHigh:
298         *reinterpret_cast<uint32_t *>(relocAddress) = static_cast<uint32_t>((gpuAddressAs64bit >> 32) & 0xffffffff);
299         break;
300     }
301 }
302 
patchInstructionsSegments(const std::vector<PatchableSegment> & instructionsSegments,std::vector<UnresolvedExternal> & outUnresolvedExternals)303 void Linker::patchInstructionsSegments(const std::vector<PatchableSegment> &instructionsSegments, std::vector<UnresolvedExternal> &outUnresolvedExternals) {
304     if (false == data.getTraits().requiresPatchingOfInstructionSegments) {
305         return;
306     }
307     UNRECOVERABLE_IF(data.getRelocationsInInstructionSegments().size() > instructionsSegments.size());
308     auto segIt = instructionsSegments.begin();
309     uint32_t segId = 0u;
310     for (auto relocsIt = data.getRelocationsInInstructionSegments().begin(), relocsEnd = data.getRelocationsInInstructionSegments().end();
311          relocsIt != relocsEnd; ++relocsIt, ++segIt, ++segId) {
312         auto &thisSegmentRelocs = *relocsIt;
313         const PatchableSegment &instSeg = *segIt;
314         for (const auto &relocation : thisSegmentRelocs) {
315             if (shouldIgnoreRelocation(relocation)) {
316                 continue;
317             }
318             UNRECOVERABLE_IF(nullptr == instSeg.hostPointer);
319             auto relocAddress = ptrOffset(instSeg.hostPointer, static_cast<uintptr_t>(relocation.offset));
320             if (relocation.symbolName == implicitArgsRelocationSymbolName) {
321                 pImplicitArgsRelocationAddresses.insert({segId, reinterpret_cast<uint32_t *>(relocAddress)});
322                 continue;
323             }
324             auto symbolIt = relocatedSymbols.find(relocation.symbolName);
325 
326             bool invalidOffset = relocation.offset + addressSizeInBytes(relocation.type) > instSeg.segmentSize;
327             bool unresolvedExternal = (symbolIt == relocatedSymbols.end());
328 
329             DEBUG_BREAK_IF(invalidOffset);
330             if (invalidOffset || unresolvedExternal) {
331                 uint32_t segId = static_cast<uint32_t>(segIt - instructionsSegments.begin());
332                 outUnresolvedExternals.push_back(UnresolvedExternal{relocation, segId, invalidOffset});
333                 continue;
334             }
335 
336             patchAddress(relocAddress, symbolIt->second, relocation);
337         }
338     }
339 }
340 
patchDataSegments(const SegmentInfo & globalVariablesSegInfo,const SegmentInfo & globalConstantsSegInfo,GraphicsAllocation * globalVariablesSeg,GraphicsAllocation * globalConstantsSeg,std::vector<UnresolvedExternal> & outUnresolvedExternals,Device * pDevice,const void * constantsInitData,const void * variablesInitData)341 void Linker::patchDataSegments(const SegmentInfo &globalVariablesSegInfo, const SegmentInfo &globalConstantsSegInfo,
342                                GraphicsAllocation *globalVariablesSeg, GraphicsAllocation *globalConstantsSeg,
343                                std::vector<UnresolvedExternal> &outUnresolvedExternals, Device *pDevice,
344                                const void *constantsInitData, const void *variablesInitData) {
345     for (const auto &relocation : data.getDataRelocations()) {
346         auto symbolIt = relocatedSymbols.find(relocation.symbolName);
347         if (symbolIt == relocatedSymbols.end()) {
348             outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
349             continue;
350         }
351         uint64_t srcGpuAddressAs64Bit = symbolIt->second.gpuAddress;
352 
353         GraphicsAllocation *dst = nullptr;
354         const void *initData = nullptr;
355         if (SegmentType::GlobalVariables == relocation.relocationSegment) {
356             dst = globalVariablesSeg;
357             initData = variablesInitData;
358         } else if (SegmentType::GlobalConstants == relocation.relocationSegment) {
359             dst = globalConstantsSeg;
360             initData = constantsInitData;
361         } else {
362             outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
363             continue;
364         }
365         UNRECOVERABLE_IF(nullptr == dst);
366 
367         auto relocType = (LinkerInput::Traits::PointerSize::Ptr32bit == data.getTraits().pointerSize) ? RelocationInfo::Type::AddressLow : relocation.type;
368         bool invalidOffset = relocation.offset + addressSizeInBytes(relocType) > dst->getUnderlyingBufferSize();
369         DEBUG_BREAK_IF(invalidOffset);
370         if (invalidOffset) {
371             outUnresolvedExternals.push_back(UnresolvedExternal{relocation});
372             continue;
373         }
374 
375         uint64_t incrementValue = 0U;
376         switch (relocType) {
377         default:
378             UNRECOVERABLE_IF(RelocationInfo::Type::Address != relocType);
379             incrementValue = srcGpuAddressAs64Bit;
380             patchIncrement<uint64_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
381             break;
382         case RelocationInfo::Type::AddressLow:
383             incrementValue = srcGpuAddressAs64Bit & 0xffffffff;
384             patchIncrement<uint32_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
385             break;
386         case RelocationInfo::Type::AddressHigh:
387             incrementValue = (srcGpuAddressAs64Bit >> 32) & 0xffffffff;
388             patchIncrement<uint32_t>(pDevice, dst, static_cast<size_t>(relocation.offset), initData, incrementValue);
389             break;
390         }
391     }
392 }
393 
constructLinkerErrorMessage(const Linker::UnresolvedExternals & unresolvedExternals,const std::vector<std::string> & instructionsSegmentsNames)394 std::string constructLinkerErrorMessage(const Linker::UnresolvedExternals &unresolvedExternals, const std::vector<std::string> &instructionsSegmentsNames) {
395     std::stringstream errorStream;
396     if (unresolvedExternals.size() == 0) {
397         errorStream << "Internal linker error";
398     } else {
399         for (const auto &unresExtern : unresolvedExternals) {
400             if (unresExtern.internalError) {
401                 errorStream << "error : internal linker error while handling symbol ";
402             } else {
403                 errorStream << "error : unresolved external symbol ";
404             }
405 
406             if (unresExtern.unresolvedRelocation.relocationSegment == NEO::SegmentType::Instructions) {
407                 errorStream << unresExtern.unresolvedRelocation.symbolName << " at offset " << unresExtern.unresolvedRelocation.offset
408                             << " in instructions segment #" << unresExtern.instructionsSegmentId;
409                 if (instructionsSegmentsNames.size() > unresExtern.instructionsSegmentId) {
410                     errorStream << " (aka " << instructionsSegmentsNames[unresExtern.instructionsSegmentId] << ")";
411                 }
412             } else {
413                 errorStream << " symbol #" << unresExtern.unresolvedRelocation.symbolName << " at offset " << unresExtern.unresolvedRelocation.offset
414                             << " in data segment #" << asString(unresExtern.unresolvedRelocation.relocationSegment);
415             }
416             errorStream << "\n";
417         }
418     }
419     return errorStream.str();
420 }
421 
constructRelocationsDebugMessage(const Linker::RelocatedSymbolsMap & relocatedSymbols)422 std::string constructRelocationsDebugMessage(const Linker::RelocatedSymbolsMap &relocatedSymbols) {
423     if (relocatedSymbols.empty()) {
424         return "";
425     }
426     std::stringstream stream;
427     stream << "Relocations debug informations :\n";
428     for (const auto &symbol : relocatedSymbols) {
429         stream << " * \"" << symbol.first << "\" [" << symbol.second.symbol.size << " bytes]";
430         stream << " " << asString(symbol.second.symbol.segment) << "_SEGMENT@" << symbol.second.symbol.offset;
431         stream << " -> " << std::hex << std::showbase << symbol.second.gpuAddress << " GPUVA" << std::dec;
432         stream << "\n";
433     }
434     return stream.str();
435 }
436 
applyDebugDataRelocations(const NEO::Elf::Elf<NEO::Elf::EI_CLASS_64> & decodedElf,ArrayRef<uint8_t> inputOutputElf,const SegmentInfo & text,const SegmentInfo & globalData,const SegmentInfo & constData)437 void Linker::applyDebugDataRelocations(const NEO::Elf::Elf<NEO::Elf::EI_CLASS_64> &decodedElf, ArrayRef<uint8_t> inputOutputElf, const SegmentInfo &text, const SegmentInfo &globalData, const SegmentInfo &constData) {
438 
439     for (auto &reloc : decodedElf.getDebugInfoRelocations()) {
440         auto targetSectionName = decodedElf.getSectionName(reloc.targetSectionIndex);
441         auto sectionName = decodedElf.getSectionName(reloc.symbolSectionIndex);
442         auto symbolAddress = decodedElf.getSymbolValue(reloc.symbolTableIndex);
443 
444         if (sectionName == Elf::SpecialSectionNames::text) {
445             symbolAddress += text.gpuAddress;
446         } else if (ConstStringRef(sectionName.c_str()).startsWith(Elf::SectionsNamesZebin::dataConst.data())) {
447             symbolAddress += constData.gpuAddress;
448         } else if (ConstStringRef(sectionName.c_str()).startsWith(Elf::SectionsNamesZebin::dataGlobal.data())) {
449             symbolAddress += globalData.gpuAddress;
450         } else {
451             // do not offset debug sections
452             if (!ConstStringRef(sectionName.c_str()).startsWith(Elf::SpecialSectionNames::debug.data())) {
453                 // skip other sections
454                 continue;
455             }
456         }
457 
458         symbolAddress += reloc.addend;
459 
460         auto targetSectionOffset = decodedElf.sectionHeaders[reloc.targetSectionIndex].header->offset;
461         auto relocLocation = reinterpret_cast<uint64_t>(inputOutputElf.begin()) + targetSectionOffset + reloc.offset;
462 
463         if (static_cast<Elf::RELOCATION_X8664_TYPE>(reloc.relocType) == Elf::RELOCATION_X8664_TYPE::R_X8664_64) {
464             *reinterpret_cast<uint64_t *>(relocLocation) = symbolAddress;
465         } else if (static_cast<Elf::RELOCATION_X8664_TYPE>(reloc.relocType) == Elf::RELOCATION_X8664_TYPE::R_X8664_32) {
466             *reinterpret_cast<uint32_t *>(relocLocation) = static_cast<uint32_t>(symbolAddress & uint32_t(-1));
467         }
468     }
469 }
470 
resolveImplicitArgs(const KernelDescriptorsT & kernelDescriptors,Device * pDevice)471 void Linker::resolveImplicitArgs(const KernelDescriptorsT &kernelDescriptors, Device *pDevice) {
472     for (auto i = 0u; i < kernelDescriptors.size(); i++) {
473         UNRECOVERABLE_IF(!kernelDescriptors[i]);
474         KernelDescriptor &kernelDescriptor = *kernelDescriptors[i];
475         auto pImplicitArgsReloc = pImplicitArgsRelocationAddresses.find(i);
476         if (pImplicitArgsReloc != pImplicitArgsRelocationAddresses.end()) {
477             UNRECOVERABLE_IF(!pDevice);
478             kernelDescriptor.kernelAttributes.flags.requiresImplicitArgs = kernelDescriptor.kernelAttributes.flags.useStackCalls || pDevice->getDebugger() != nullptr;
479             if (kernelDescriptor.kernelAttributes.flags.requiresImplicitArgs) {
480                 *pImplicitArgsReloc->second = sizeof(ImplicitArgs);
481             } else {
482                 *pImplicitArgsReloc->second = 0u;
483             }
484         }
485     }
486 }
487 
resolveBuiltins(Device * pDevice,UnresolvedExternals & outUnresolvedExternals,const std::vector<PatchableSegment> & instructionsSegments)488 void Linker::resolveBuiltins(Device *pDevice, UnresolvedExternals &outUnresolvedExternals, const std::vector<PatchableSegment> &instructionsSegments) {
489     int vecIndex = static_cast<int>(outUnresolvedExternals.size() - 1u);
490     for (; vecIndex >= 0; --vecIndex) {
491         if (outUnresolvedExternals[vecIndex].unresolvedRelocation.symbolName == subDeviceID) {
492             RelocatedSymbol symbol;
493             symbol.gpuAddress = static_cast<uintptr_t>(pDevice->getDefaultEngine().commandStreamReceiver->getWorkPartitionAllocationGpuAddress());
494             auto relocAddress = ptrOffset(instructionsSegments[outUnresolvedExternals[vecIndex].instructionsSegmentId].hostPointer,
495                                           static_cast<uintptr_t>(outUnresolvedExternals[vecIndex].unresolvedRelocation.offset));
496 
497             NEO::Linker::patchAddress(relocAddress, symbol, outUnresolvedExternals[vecIndex].unresolvedRelocation);
498 
499             outUnresolvedExternals[vecIndex] = outUnresolvedExternals[outUnresolvedExternals.size() - 1u];
500             outUnresolvedExternals.resize(outUnresolvedExternals.size() - 1u);
501         }
502     }
503 }
504 } // namespace NEO