1 //===---- ELF_x86_64.cpp -JIT linker implementation for ELF/x86-64 ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // ELF/x86-64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h"
14 #include "BasicGOTAndStubsBuilder.h"
15 #include "JITLinkGeneric.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/Object/ELFObjectFile.h"
18 #include "llvm/Support/Endian.h"
19 
20 #define DEBUG_TYPE "jitlink"
21 
22 using namespace llvm;
23 using namespace llvm::jitlink;
24 using namespace llvm::jitlink::ELF_x86_64_Edges;
25 
26 namespace {
27 
28 class ELF_x86_64_GOTAndStubsBuilder
29     : public BasicGOTAndStubsBuilder<ELF_x86_64_GOTAndStubsBuilder> {
30 public:
31   static const uint8_t NullGOTEntryContent[8];
32   static const uint8_t StubContent[6];
33 
34   ELF_x86_64_GOTAndStubsBuilder(LinkGraph &G)
35       : BasicGOTAndStubsBuilder<ELF_x86_64_GOTAndStubsBuilder>(G) {}
36 
37   bool isGOTEdge(Edge &E) const {
38     return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
39   }
40 
41   Symbol &createGOTEntry(Symbol &Target) {
42     auto &GOTEntryBlock = G.createContentBlock(
43         getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
44     GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
45     return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
46   }
47 
48   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
49     assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
50            "Not a GOT edge?");
51     // If this is a PCRel32GOT then change it to an ordinary PCRel32. If it is
52     // a PCRel32GOTLoad then leave it as-is for now. We will use the kind to
53     // check for GOT optimization opportunities in the
54     // optimizeMachO_x86_64_GOTAndStubs pass below.
55     if (E.getKind() == PCRel32GOT)
56       E.setKind(PCRel32);
57 
58     E.setTarget(GOTEntry);
59     // Leave the edge addend as-is.
60   }
61 
62   bool isExternalBranchEdge(Edge &E) {
63     return E.getKind() == Branch32 && !E.getTarget().isDefined();
64   }
65 
66   Symbol &createStub(Symbol &Target) {
67     auto &StubContentBlock =
68         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
69     // Re-use GOT entries for stub targets.
70     auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
71     StubContentBlock.addEdge(PCRel32, 2, GOTEntrySymbol, 0);
72     return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
73   }
74 
75   void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
76     assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
77 
78     // Set the edge kind to Branch32ToStub. We will use this to check for stub
79     // optimization opportunities in the optimize ELF_x86_64_GOTAndStubs pass
80     // below.
81     E.setKind(Branch32ToStub);
82     E.setTarget(Stub);
83   }
84 
85 private:
86   Section &getGOTSection() {
87     if (!GOTSection)
88       GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
89     return *GOTSection;
90   }
91 
92   Section &getStubsSection() {
93     if (!StubsSection) {
94       auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
95           sys::Memory::MF_READ | sys::Memory::MF_EXEC);
96       StubsSection = &G.createSection("$__STUBS", StubsProt);
97     }
98     return *StubsSection;
99   }
100 
101   StringRef getGOTEntryBlockContent() {
102     return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
103                      sizeof(NullGOTEntryContent));
104   }
105 
106   StringRef getStubBlockContent() {
107     return StringRef(reinterpret_cast<const char *>(StubContent),
108                      sizeof(StubContent));
109   }
110 
111   Section *GOTSection = nullptr;
112   Section *StubsSection = nullptr;
113 };
114 
115 const char *const DwarfSectionNames[] = {
116 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
117   ELF_NAME,
118 #include "llvm/BinaryFormat/Dwarf.def"
119 #undef HANDLE_DWARF_SECTION
120 };
121 
122 } // namespace
123 
124 const uint8_t ELF_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
125     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
126 const uint8_t ELF_x86_64_GOTAndStubsBuilder::StubContent[6] = {
127     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
128 
129 static const char *CommonSectionName = "__common";
130 static Error optimizeELF_x86_64_GOTAndStubs(LinkGraph &G) {
131   LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
132 
133   for (auto *B : G.blocks())
134     for (auto &E : B->edges())
135       if (E.getKind() == PCRel32GOTLoad) {
136         // Replace GOT load with LEA only for MOVQ instructions.
137         constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b};
138         if (E.getOffset() < 3 ||
139             strncmp(B->getContent().data() + E.getOffset() - 3,
140                     reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0)
141           continue;
142 
143         auto &GOTBlock = E.getTarget().getBlock();
144         assert(GOTBlock.getSize() == G.getPointerSize() &&
145                "GOT entry block should be pointer sized");
146         assert(GOTBlock.edges_size() == 1 &&
147                "GOT entry should only have one outgoing edge");
148 
149         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
150         JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
151         JITTargetAddress TargetAddr = GOTTarget.getAddress();
152 
153         int64_t Displacement = TargetAddr - EdgeAddr + 4;
154         if (Displacement >= std::numeric_limits<int32_t>::min() &&
155             Displacement <= std::numeric_limits<int32_t>::max()) {
156           // Change the edge kind as we don't go through GOT anymore. This is
157           // for formal correctness only. Technically, the two relocation kinds
158           // are resolved the same way.
159           E.setKind(PCRel32);
160           E.setTarget(GOTTarget);
161           auto *BlockData = reinterpret_cast<uint8_t *>(
162               const_cast<char *>(B->getContent().data()));
163           BlockData[E.getOffset() - 2] = 0x8d;
164           LLVM_DEBUG({
165             dbgs() << "  Replaced GOT load wih LEA:\n    ";
166             printEdge(dbgs(), *B, E, getELFX86RelocationKindName(E.getKind()));
167             dbgs() << "\n";
168           });
169         }
170       } else if (E.getKind() == Branch32ToStub) {
171         auto &StubBlock = E.getTarget().getBlock();
172         assert(StubBlock.getSize() ==
173                    sizeof(ELF_x86_64_GOTAndStubsBuilder::StubContent) &&
174                "Stub block should be stub sized");
175         assert(StubBlock.edges_size() == 1 &&
176                "Stub block should only have one outgoing edge");
177 
178         auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
179         assert(GOTBlock.getSize() == G.getPointerSize() &&
180                "GOT block should be pointer sized");
181         assert(GOTBlock.edges_size() == 1 &&
182                "GOT block should only have one outgoing edge");
183 
184         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
185         JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
186         JITTargetAddress TargetAddr = GOTTarget.getAddress();
187 
188         int64_t Displacement = TargetAddr - EdgeAddr + 4;
189         if (Displacement >= std::numeric_limits<int32_t>::min() &&
190             Displacement <= std::numeric_limits<int32_t>::max()) {
191           E.setKind(Branch32);
192           E.setTarget(GOTTarget);
193           LLVM_DEBUG({
194             dbgs() << "  Replaced stub branch with direct branch:\n    ";
195             printEdge(dbgs(), *B, E, getELFX86RelocationKindName(E.getKind()));
196             dbgs() << "\n";
197           });
198         }
199       }
200 
201   return Error::success();
202 }
203 
204 static bool isDwarfSection(StringRef SectionName) {
205   for (auto &DwarfSectionName : DwarfSectionNames)
206     if (SectionName == DwarfSectionName)
207       return true;
208   return false;
209 }
210 
211 namespace llvm {
212 namespace jitlink {
213 
214 // This should become a template as the ELFFile is so a lot of this could become
215 // generic
216 class ELFLinkGraphBuilder_x86_64 {
217 
218 private:
219   Section *CommonSection = nullptr;
220   // TODO hack to get this working
221   // Find a better way
222   using SymbolTable = object::ELFFile<object::ELF64LE>::Elf_Shdr;
223   // For now we just assume
224   using SymbolMap = std::map<int32_t, Symbol *>;
225   SymbolMap JITSymbolTable;
226 
227   Section &getCommonSection() {
228     if (!CommonSection) {
229       auto Prot = static_cast<sys::Memory::ProtectionFlags>(
230           sys::Memory::MF_READ | sys::Memory::MF_WRITE);
231       CommonSection = &G->createSection(CommonSectionName, Prot);
232     }
233     return *CommonSection;
234   }
235 
236   static Expected<ELF_x86_64_Edges::ELFX86RelocationKind>
237   getRelocationKind(const uint32_t Type) {
238     switch (Type) {
239     case ELF::R_X86_64_PC32:
240       return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32;
241     case ELF::R_X86_64_64:
242       return ELF_x86_64_Edges::ELFX86RelocationKind::Pointer64;
243     case ELF::R_X86_64_GOTPCREL:
244     case ELF::R_X86_64_GOTPCRELX:
245     case ELF::R_X86_64_REX_GOTPCRELX:
246       return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32GOTLoad;
247     case ELF::R_X86_64_PLT32:
248       return ELF_x86_64_Edges::ELFX86RelocationKind::Branch32;
249     }
250     return make_error<JITLinkError>("Unsupported x86-64 relocation:" +
251                                     formatv("{0:d}", Type));
252   }
253 
254   std::unique_ptr<LinkGraph> G;
255   // This could be a template
256   const object::ELFFile<object::ELF64LE> &Obj;
257   object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections;
258   SymbolTable SymTab;
259 
260   bool isRelocatable() { return Obj.getHeader().e_type == llvm::ELF::ET_REL; }
261 
262   support::endianness
263   getEndianness(const object::ELFFile<object::ELF64LE> &Obj) {
264     return Obj.isLE() ? support::little : support::big;
265   }
266 
267   // This could also just become part of a template
268   unsigned getPointerSize(const object::ELFFile<object::ELF64LE> &Obj) {
269     return Obj.getHeader().getFileClass() == ELF::ELFCLASS64 ? 8 : 4;
270   }
271 
272   // We don't technically need this right now
273   // But for now going to keep it as it helps me to debug things
274 
275   Error createNormalizedSymbols() {
276     LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
277 
278     for (auto SecRef : sections) {
279       if (SecRef.sh_type != ELF::SHT_SYMTAB &&
280           SecRef.sh_type != ELF::SHT_DYNSYM)
281         continue;
282 
283       auto Symbols = Obj.symbols(&SecRef);
284       // TODO: Currently I use this function to test things
285       // I also want to leave it to see if its common between MACH and elf
286       // so for now I just want to continue even if there is an error
287       if (errorToBool(Symbols.takeError()))
288         continue;
289 
290       auto StrTabSec = Obj.getSection(SecRef.sh_link);
291       if (!StrTabSec)
292         return StrTabSec.takeError();
293       auto StringTable = Obj.getStringTable(**StrTabSec);
294       if (!StringTable)
295         return StringTable.takeError();
296 
297       for (auto SymRef : *Symbols) {
298         Optional<StringRef> Name;
299 
300         if (auto NameOrErr = SymRef.getName(*StringTable))
301           Name = *NameOrErr;
302         else
303           return NameOrErr.takeError();
304 
305         LLVM_DEBUG({
306           dbgs() << "  value = " << formatv("{0:x16}", SymRef.getValue())
307                  << ", type = " << formatv("{0:x2}", SymRef.getType())
308                  << ", binding = " << formatv("{0:x2}", SymRef.getBinding())
309                  << ", size = "
310                  << formatv("{0:x16}", static_cast<uint64_t>(SymRef.st_size))
311                  << ", info = " << formatv("{0:x2}", SymRef.st_info)
312                  << " :" << (Name ? *Name : "<anonymous symbol>") << "\n";
313         });
314       }
315     }
316     return Error::success();
317   }
318 
319   Error createNormalizedSections() {
320     LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
321     for (auto &SecRef : sections) {
322       auto Name = Obj.getSectionName(SecRef);
323       if (!Name)
324         return Name.takeError();
325 
326       // Skip Dwarf sections.
327       if (isDwarfSection(*Name)) {
328         LLVM_DEBUG({
329           dbgs() << *Name
330                  << " is a debug section: No graph section will be created.\n";
331         });
332         continue;
333       }
334 
335       sys::Memory::ProtectionFlags Prot;
336       if (SecRef.sh_flags & ELF::SHF_EXECINSTR) {
337         Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
338                                                          sys::Memory::MF_EXEC);
339       } else {
340         Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
341                                                          sys::Memory::MF_WRITE);
342       }
343       uint64_t Address = SecRef.sh_addr;
344       uint64_t Size = SecRef.sh_size;
345       uint64_t Flags = SecRef.sh_flags;
346       uint64_t Alignment = SecRef.sh_addralign;
347       const char *Data = nullptr;
348       // for now we just use this to skip the "undefined" section, probably need
349       // to revist
350       if (Size == 0)
351         continue;
352 
353       // FIXME: Use flags.
354       (void)Flags;
355 
356       LLVM_DEBUG({
357         dbgs() << "  " << *Name << ": " << formatv("{0:x16}", Address) << " -- "
358                << formatv("{0:x16}", Address + Size) << ", align: " << Alignment
359                << " Flags: " << formatv("{0:x}", Flags) << "\n";
360       });
361 
362       if (SecRef.sh_type != ELF::SHT_NOBITS) {
363         // .sections() already checks that the data is not beyond the end of
364         // file
365         auto contents = Obj.getSectionContentsAsArray<char>(SecRef);
366         if (!contents)
367           return contents.takeError();
368 
369         Data = contents->data();
370         // TODO protection flags.
371         // for now everything is
372         auto &section = G->createSection(*Name, Prot);
373         // Do this here because we have it, but move it into graphify later
374         G->createContentBlock(section, StringRef(Data, Size), Address,
375                               Alignment, 0);
376         if (SecRef.sh_type == ELF::SHT_SYMTAB)
377           // TODO: Dynamic?
378           SymTab = SecRef;
379       } else {
380         auto &Section = G->createSection(*Name, Prot);
381         G->createZeroFillBlock(Section, Size, Address, Alignment, 0);
382       }
383     }
384 
385     return Error::success();
386   }
387 
388   Error addRelocations() {
389     LLVM_DEBUG(dbgs() << "Adding relocations\n");
390     // TODO a partern is forming of iterate some sections but only give me
391     // ones I am interested, i should abstract that concept some where
392     for (auto &SecRef : sections) {
393       if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
394         continue;
395       // TODO can the elf obj file do this for me?
396       if (SecRef.sh_type == ELF::SHT_REL)
397         return make_error<llvm::StringError>("Shouldn't have REL in x64",
398                                              llvm::inconvertibleErrorCode());
399 
400       auto RelSectName = Obj.getSectionName(SecRef);
401       if (!RelSectName)
402         return RelSectName.takeError();
403 
404       LLVM_DEBUG({
405         dbgs() << "Adding relocations from section " << *RelSectName << "\n";
406       });
407       // Deal with .eh_frame later
408       if (*RelSectName == StringRef(".rela.eh_frame"))
409         continue;
410 
411       auto UpdateSection = Obj.getSection(SecRef.sh_info);
412       if (!UpdateSection)
413         return UpdateSection.takeError();
414 
415       auto UpdateSectionName = Obj.getSectionName(**UpdateSection);
416       if (!UpdateSectionName)
417         return UpdateSectionName.takeError();
418 
419       // Don't process relocations for debug sections.
420       if (isDwarfSection(*UpdateSectionName)) {
421         LLVM_DEBUG({
422           dbgs() << "  Target is dwarf section " << *UpdateSectionName
423                  << ". Skipping.\n";
424         });
425         continue;
426       } else
427         LLVM_DEBUG({
428           dbgs() << "  For target section " << *UpdateSectionName << "\n";
429         });
430 
431       auto JITSection = G->findSectionByName(*UpdateSectionName);
432       if (!JITSection)
433         return make_error<llvm::StringError>(
434             "Refencing a a section that wasn't added to graph" +
435                 *UpdateSectionName,
436             llvm::inconvertibleErrorCode());
437 
438       auto Relocations = Obj.relas(SecRef);
439       if (!Relocations)
440         return Relocations.takeError();
441 
442       for (const auto &Rela : *Relocations) {
443         auto Type = Rela.getType(false);
444 
445         LLVM_DEBUG({
446           dbgs() << "Relocation Type: " << Type << "\n"
447                  << "Name: " << Obj.getRelocationTypeName(Type) << "\n";
448         });
449         auto SymbolIndex = Rela.getSymbol(false);
450         auto Symbol = Obj.getRelocationSymbol(Rela, &SymTab);
451         if (!Symbol)
452           return Symbol.takeError();
453 
454         auto BlockToFix = *(JITSection->blocks().begin());
455         auto *TargetSymbol = JITSymbolTable[SymbolIndex];
456 
457         if (!TargetSymbol) {
458           return make_error<llvm::StringError>(
459               "Could not find symbol at given index, did you add it to "
460               "JITSymbolTable? index: " + std::to_string(SymbolIndex)
461               + ", shndx: " + std::to_string((*Symbol)->st_shndx) +
462                   " Size of table: " + std::to_string(JITSymbolTable.size()),
463               llvm::inconvertibleErrorCode());
464         }
465         uint64_t Addend = Rela.r_addend;
466         JITTargetAddress FixupAddress =
467             (*UpdateSection)->sh_addr + Rela.r_offset;
468 
469         LLVM_DEBUG({
470           dbgs() << "Processing relocation at "
471                  << format("0x%016" PRIx64, FixupAddress) << "\n";
472         });
473         auto Kind = getRelocationKind(Type);
474         if (!Kind)
475           return Kind.takeError();
476 
477         LLVM_DEBUG({
478           Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
479                   Addend);
480           printEdge(dbgs(), *BlockToFix, GE,
481                     getELFX86RelocationKindName(*Kind));
482           dbgs() << "\n";
483         });
484         BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
485                             *TargetSymbol, Addend);
486       }
487     }
488     return Error::success();
489   }
490 
491   Error graphifyRegularSymbols() {
492 
493     // TODO: ELF supports beyond SHN_LORESERVE,
494     // need to perf test how a vector vs map handles those cases
495 
496     std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>>
497         SecIndexToSymbols;
498 
499     LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
500 
501     for (auto SecRef : sections) {
502 
503       if (SecRef.sh_type != ELF::SHT_SYMTAB &&
504           SecRef.sh_type != ELF::SHT_DYNSYM)
505         continue;
506       auto Symbols = Obj.symbols(&SecRef);
507       if (!Symbols)
508         return Symbols.takeError();
509 
510       auto StrTabSec = Obj.getSection(SecRef.sh_link);
511       if (!StrTabSec)
512         return StrTabSec.takeError();
513       auto StringTable = Obj.getStringTable(**StrTabSec);
514       if (!StringTable)
515         return StringTable.takeError();
516       auto Name = Obj.getSectionName(SecRef);
517       if (!Name)
518         return Name.takeError();
519 
520       LLVM_DEBUG(dbgs() << "Processing symbol section " << *Name << ":\n");
521 
522       auto Section = G->findSectionByName(*Name);
523       if (!Section)
524         return make_error<llvm::StringError>("Could not find a section " +
525                                              *Name,
526                                              llvm::inconvertibleErrorCode());
527       // we only have one for now
528       auto blocks = Section->blocks();
529       if (blocks.empty())
530         return make_error<llvm::StringError>("Section has no block",
531                                              llvm::inconvertibleErrorCode());
532       int SymbolIndex = -1;
533       for (auto SymRef : *Symbols) {
534         ++SymbolIndex;
535         auto Type = SymRef.getType();
536 
537         if (Type == ELF::STT_FILE || SymbolIndex == 0)
538           continue;
539         // these should do it for now
540         // if(Type != ELF::STT_NOTYPE &&
541         //   Type != ELF::STT_OBJECT &&
542         //   Type != ELF::STT_FUNC    &&
543         //   Type != ELF::STT_SECTION &&
544         //   Type != ELF::STT_COMMON) {
545         //     continue;
546         //   }
547         std::pair<Linkage, Scope> bindings;
548         auto Name = SymRef.getName(*StringTable);
549         // I am not sure on If this is going to hold as an invariant. Revisit.
550         if (!Name)
551           return Name.takeError();
552 
553         if (SymRef.isCommon()) {
554           // Symbols in SHN_COMMON refer to uninitialized data. The st_value
555           // field holds alignment constraints.
556           Symbol &S =
557               G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0,
558                                  SymRef.st_size, SymRef.getValue(), false);
559           JITSymbolTable[SymbolIndex] = &S;
560           continue;
561         }
562 
563         // TODO: weak and hidden
564         if (SymRef.isExternal())
565           bindings = {Linkage::Strong, Scope::Default};
566         else
567           bindings = {Linkage::Strong, Scope::Local};
568 
569         if (SymRef.isDefined() &&
570             (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT ||
571              Type == ELF::STT_SECTION)) {
572 
573           auto DefinedSection = Obj.getSection(SymRef.st_shndx);
574           if (!DefinedSection)
575             return DefinedSection.takeError();
576           auto sectName = Obj.getSectionName(**DefinedSection);
577           if (!sectName)
578             return Name.takeError();
579 
580           // Skip debug section symbols.
581           if (isDwarfSection(*sectName))
582             continue;
583 
584           auto JitSection = G->findSectionByName(*sectName);
585           if (!JitSection)
586             return make_error<llvm::StringError>(
587                 "Could not find the JitSection " + *sectName,
588                 llvm::inconvertibleErrorCode());
589           auto bs = JitSection->blocks();
590           if (bs.empty())
591             return make_error<llvm::StringError>(
592                 "Section has no block", llvm::inconvertibleErrorCode());
593 
594           auto B = *bs.begin();
595           LLVM_DEBUG({ dbgs() << "  " << *Name << " at index " << SymbolIndex << "\n"; });
596           if (SymRef.getType() == ELF::STT_SECTION)
597             *Name = *sectName;
598           auto &S = G->addDefinedSymbol(
599               *B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first,
600               bindings.second, SymRef.getType() == ELF::STT_FUNC, false);
601           JITSymbolTable[SymbolIndex] = &S;
602         } else if (SymRef.isUndefined() && SymRef.isExternal()) {
603           auto &S = G->addExternalSymbol(*Name, SymRef.st_size, bindings.first);
604           JITSymbolTable[SymbolIndex] = &S;
605         } else
606           LLVM_DEBUG({
607               dbgs()
608                 << "Not creating graph symbol for normalized symbol at index "
609                 << SymbolIndex << ", \"" << *Name << "\"\n";
610             });
611 
612         // TODO: The following has to be implmented.
613         // leaving commented out to save time for future patchs
614         /*
615           G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size,
616           Linkage::Strong, Scope::Default, false);
617         */
618       }
619     }
620     return Error::success();
621   }
622 
623 public:
624   ELFLinkGraphBuilder_x86_64(StringRef FileName,
625                              const object::ELFFile<object::ELF64LE> &Obj)
626       : G(std::make_unique<LinkGraph>(FileName.str(),
627                                       Triple("x86_64-unknown-linux"),
628                                       getPointerSize(Obj), getEndianness(Obj))),
629         Obj(Obj) {}
630 
631   Expected<std::unique_ptr<LinkGraph>> buildGraph() {
632     // Sanity check: we only operate on relocatable objects.
633     if (!isRelocatable())
634       return make_error<JITLinkError>("Object is not a relocatable ELF");
635 
636     auto Secs = Obj.sections();
637 
638     if (!Secs) {
639       return Secs.takeError();
640     }
641     sections = *Secs;
642 
643     if (auto Err = createNormalizedSections())
644       return std::move(Err);
645 
646     if (auto Err = createNormalizedSymbols())
647       return std::move(Err);
648 
649     if (auto Err = graphifyRegularSymbols())
650       return std::move(Err);
651 
652     if (auto Err = addRelocations())
653       return std::move(Err);
654 
655     return std::move(G);
656   }
657 };
658 
659 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
660   friend class JITLinker<ELFJITLinker_x86_64>;
661 
662 public:
663   ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
664                       std::unique_ptr<LinkGraph> G,
665                       PassConfiguration PassConfig)
666       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
667 
668 private:
669   StringRef getEdgeKindName(Edge::Kind R) const override {
670     return getELFX86RelocationKindName(R);
671   }
672 
673   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
674     using namespace ELF_x86_64_Edges;
675     using namespace llvm::support;
676     char *FixupPtr = BlockWorkingMem + E.getOffset();
677     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
678     switch (E.getKind()) {
679     case ELFX86RelocationKind::Branch32:
680     case ELFX86RelocationKind::Branch32ToStub:
681     case ELFX86RelocationKind::PCRel32:
682     case ELFX86RelocationKind::PCRel32GOTLoad: {
683       int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
684       endian::write32le(FixupPtr, Value);
685       break;
686     }
687     case ELFX86RelocationKind::Pointer64: {
688       int64_t Value = E.getTarget().getAddress() + E.getAddend();
689       endian::write64le(FixupPtr, Value);
690       break;
691     }
692     }
693     return Error::success();
694   }
695 };
696 
697 Expected<std::unique_ptr<LinkGraph>>
698 createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer) {
699   LLVM_DEBUG({
700     dbgs() << "Building jitlink graph for new input "
701            << ObjectBuffer.getBufferIdentifier() << "...\n";
702   });
703 
704   auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
705   if (!ELFObj)
706     return ELFObj.takeError();
707 
708   auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
709   return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
710                                     ELFObjFile.getELFFile())
711       .buildGraph();
712 }
713 
714 void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
715                      std::unique_ptr<JITLinkContext> Ctx) {
716   PassConfiguration Config;
717 
718   // Construct a JITLinker and run the link function.
719   // Add a mark-live pass.
720   if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
721     Config.PrePrunePasses.push_back(std::move(MarkLive));
722   else
723     Config.PrePrunePasses.push_back(markAllSymbolsLive);
724 
725   // Add an in-place GOT/Stubs pass.
726   Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
727     ELF_x86_64_GOTAndStubsBuilder(G).run();
728     return Error::success();
729   });
730 
731   // Add GOT/Stubs optimizer pass.
732   Config.PreFixupPasses.push_back(optimizeELF_x86_64_GOTAndStubs);
733 
734   if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
735     return Ctx->notifyFailed(std::move(Err));
736 
737   ELFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
738 }
739 StringRef getELFX86RelocationKindName(Edge::Kind R) {
740   switch (R) {
741   case PCRel32:
742     return "PCRel32";
743   case Pointer64:
744     return "Pointer64";
745   case PCRel32GOTLoad:
746     return "PCRel32GOTLoad";
747   case Branch32:
748     return "Branch32";
749   case Branch32ToStub:
750     return "Branch32ToStub";
751   }
752   return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
753 }
754 } // end namespace jitlink
755 } // end namespace llvm
756