]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
Upgrade to version 3.2.3
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / ExecutionEngine / JITLink / ELF_x86_64.cpp
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 "JITLinkGeneric.h"
15 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
16 #include "llvm/Object/ELFObjectFile.h"
17
18 #define DEBUG_TYPE "jitlink"
19
20 using namespace llvm;
21 using namespace llvm::jitlink;
22
23 static const char *CommonSectionName = "__common";
24
25 namespace llvm {
26 namespace jitlink {
27
28 // This should become a template as the ELFFile is so a lot of this could become
29 // generic
30 class ELFLinkGraphBuilder_x86_64 {
31
32 private:
33   Section *CommonSection = nullptr;
34   // TODO hack to get this working
35   // Find a better way
36   using SymbolTable = object::ELFFile<object::ELF64LE>::Elf_Shdr;
37   // For now we just assume
38   std::map<int32_t, Symbol *> JITSymbolTable;
39
40   Section &getCommonSection() {
41     if (!CommonSection) {
42       auto Prot = static_cast<sys::Memory::ProtectionFlags>(
43           sys::Memory::MF_READ | sys::Memory::MF_WRITE);
44       CommonSection = &G->createSection(CommonSectionName, Prot);
45     }
46     return *CommonSection;
47   }
48
49   static Expected<ELF_x86_64_Edges::ELFX86RelocationKind>
50   getRelocationKind(const uint32_t Type) {
51     switch (Type) {
52     case ELF::R_X86_64_PC32:
53       return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32;
54     }
55     return make_error<JITLinkError>("Unsupported x86-64 relocation:" +
56                                     formatv("{0:d}", Type));
57   }
58
59   std::unique_ptr<LinkGraph> G;
60   // This could be a template
61   const object::ELFFile<object::ELF64LE> &Obj;
62   object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections;
63   SymbolTable SymTab;
64
65   bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; }
66
67   support::endianness
68   getEndianness(const object::ELFFile<object::ELF64LE> &Obj) {
69     return Obj.isLE() ? support::little : support::big;
70   }
71
72   // This could also just become part of a template
73   unsigned getPointerSize(const object::ELFFile<object::ELF64LE> &Obj) {
74     return Obj.getHeader()->getFileClass() == ELF::ELFCLASS64 ? 8 : 4;
75   }
76
77   // We don't technically need this right now
78   // But for now going to keep it as it helps me to debug things
79
80   Error createNormalizedSymbols() {
81     LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
82
83     for (auto SecRef : sections) {
84       if (SecRef.sh_type != ELF::SHT_SYMTAB &&
85           SecRef.sh_type != ELF::SHT_DYNSYM)
86         continue;
87
88       auto Symbols = Obj.symbols(&SecRef);
89       // TODO: Currently I use this function to test things 
90       // I also want to leave it to see if its common between MACH and elf
91       // so for now I just want to continue even if there is an error
92       if (errorToBool(Symbols.takeError()))
93         continue;
94
95       auto StrTabSec = Obj.getSection(SecRef.sh_link);
96       if (!StrTabSec)
97         return StrTabSec.takeError();
98       auto StringTable = Obj.getStringTable(*StrTabSec);
99       if (!StringTable)
100         return StringTable.takeError();
101
102       for (auto SymRef : *Symbols) {
103         Optional<StringRef> Name;
104         uint64_t Size = 0;
105
106         // FIXME: Read size.
107         (void)Size;
108
109         if (auto NameOrErr = SymRef.getName(*StringTable))
110           Name = *NameOrErr;
111         else
112           return NameOrErr.takeError();
113
114         LLVM_DEBUG({
115           dbgs() << "  ";
116           if (!Name)
117             dbgs() << "<anonymous symbol>";
118           else
119             dbgs() << *Name;
120           dbgs() << ": value = " << formatv("{0:x16}", SymRef.getValue())
121                  << ", type = " << formatv("{0:x2}", SymRef.getType())
122                  << ", binding = " << SymRef.getBinding()
123                  << ", size =" << Size;
124           dbgs() << "\n";
125         });
126       }
127     }
128     return Error::success();
129   }
130
131   Error createNormalizedSections() {
132     LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
133     for (auto &SecRef : sections) {
134       auto Name = Obj.getSectionName(&SecRef);
135       if (!Name)
136         return Name.takeError();
137       sys::Memory::ProtectionFlags Prot;
138       if (SecRef.sh_flags & ELF::SHF_EXECINSTR) {
139         Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
140                                                          sys::Memory::MF_EXEC);
141       } else {
142         Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
143                                                          sys::Memory::MF_WRITE);
144       }
145       uint64_t Address = SecRef.sh_addr;
146       uint64_t Size = SecRef.sh_size;
147       uint64_t Flags = SecRef.sh_flags;
148       uint64_t Alignment = SecRef.sh_addralign;
149       const char *Data = nullptr;
150       // TODO: figure out what it is that has 0 size no name and address
151       // 0000-0000
152       if (Size == 0)
153         continue;
154
155       // FIXME: Use flags.
156       (void)Flags;
157
158       LLVM_DEBUG({
159         dbgs() << "  " << *Name << ": " << formatv("{0:x16}", Address) << " -- "
160                << formatv("{0:x16}", Address + Size) << ", align: " << Alignment
161                << " Flags:" << Flags << "\n";
162       });
163
164       if (SecRef.sh_type != ELF::SHT_NOBITS) {
165         // .sections() already checks that the data is not beyond the end of
166         // file
167         auto contents = Obj.getSectionContentsAsArray<char>(&SecRef);
168         if (!contents)
169           return contents.takeError();
170
171         Data = contents->data();
172         // TODO protection flags.
173         // for now everything is
174         auto &section = G->createSection(*Name, Prot);
175         // Do this here because we have it, but move it into graphify later
176         G->createContentBlock(section, StringRef(Data, Size), Address,
177                               Alignment, 0);
178         if (SecRef.sh_type == ELF::SHT_SYMTAB)
179           // TODO: Dynamic?
180           SymTab = SecRef;
181       }
182     }
183
184     return Error::success();
185   }
186
187   Error addRelocations() {
188     LLVM_DEBUG(dbgs() << "Adding relocations\n");
189     // TODO a partern is forming of iterate some sections but only give me
190     // ones I am interested, i should abstract that concept some where
191     for (auto &SecRef : sections) {
192       if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
193         continue;
194       // TODO can the elf obj file do this for me?
195       if (SecRef.sh_type == ELF::SHT_REL)
196         return make_error<llvm::StringError>("Shouldn't have REL in x64",
197                                              llvm::inconvertibleErrorCode());
198
199       auto RelSectName = Obj.getSectionName(&SecRef);
200       if (!RelSectName)
201         return RelSectName.takeError();
202       // Deal with .eh_frame later
203       if (*RelSectName == StringRef(".rela.eh_frame"))
204         continue;
205
206       auto UpdateSection = Obj.getSection(SecRef.sh_info);
207       if (!UpdateSection)
208         return UpdateSection.takeError();
209
210       auto UpdateSectionName = Obj.getSectionName(*UpdateSection);
211       if (!UpdateSectionName)
212         return UpdateSectionName.takeError();
213
214       auto JITSection = G->findSectionByName(*UpdateSectionName);
215       if (!JITSection)
216         return make_error<llvm::StringError>(
217             "Refencing a a section that wasn't added to graph" +
218                 *UpdateSectionName,
219             llvm::inconvertibleErrorCode());
220
221       auto Relocations = Obj.relas(&SecRef);
222       if (!Relocations)
223         return Relocations.takeError();
224
225       for (const auto &Rela : *Relocations) {
226         auto Type = Rela.getType(false);
227
228         LLVM_DEBUG({
229           dbgs() << "Relocation Type: " << Type << "\n"
230                  << "Name: " << Obj.getRelocationTypeName(Type) << "\n";
231         });
232
233         auto Symbol = Obj.getRelocationSymbol(&Rela, &SymTab);
234         if (!Symbol)
235           return Symbol.takeError();
236
237         auto BlockToFix = *(JITSection->blocks().begin());
238         auto TargetSymbol = JITSymbolTable[(*Symbol)->st_shndx];
239         uint64_t Addend = Rela.r_addend;
240         JITTargetAddress FixupAddress =
241             (*UpdateSection)->sh_addr + Rela.r_offset;
242
243         LLVM_DEBUG({
244           dbgs() << "Processing relocation at "
245                  << format("0x%016" PRIx64, FixupAddress) << "\n";
246         });
247         auto Kind = getRelocationKind(Type);
248         if (!Kind)
249           return Kind.takeError();
250
251         LLVM_DEBUG({
252           Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
253                   Addend);
254           // TODO a mapping of KIND => type then call getRelocationTypeName4
255           printEdge(dbgs(), *BlockToFix, GE, StringRef(""));
256           dbgs() << "\n";
257         });
258         BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
259                             *TargetSymbol, Addend);
260       }
261     }
262     return Error::success();
263   }
264
265   Error graphifyRegularSymbols() {
266
267     // TODO: ELF supports beyond SHN_LORESERVE,
268     // need to perf test how a vector vs map handles those cases
269
270     std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>>
271         SecIndexToSymbols;
272
273     LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
274
275     for (auto SecRef : sections) {
276
277       if (SecRef.sh_type != ELF::SHT_SYMTAB &&
278           SecRef.sh_type != ELF::SHT_DYNSYM)
279         continue;
280       auto Symbols = Obj.symbols(&SecRef);
281       if (!Symbols)
282         return Symbols.takeError();
283
284       auto StrTabSec = Obj.getSection(SecRef.sh_link);
285       if (!StrTabSec)
286         return StrTabSec.takeError();
287       auto StringTable = Obj.getStringTable(*StrTabSec);
288       if (!StringTable)
289         return StringTable.takeError();
290       auto Name = Obj.getSectionName(&SecRef);
291       if (!Name)
292         return Name.takeError();
293       auto Section = G->findSectionByName(*Name);
294       if (!Section)
295         return make_error<llvm::StringError>("Could not find a section",
296                                              llvm::inconvertibleErrorCode());
297       // we only have one for now
298       auto blocks = Section->blocks();
299       if (blocks.empty())
300         return make_error<llvm::StringError>("Section has no block",
301                                              llvm::inconvertibleErrorCode());
302
303       for (auto SymRef : *Symbols) {
304         auto Type = SymRef.getType();
305         if (Type == ELF::STT_NOTYPE || Type == ELF::STT_FILE)
306           continue;
307         // these should do it for now
308         // if(Type != ELF::STT_NOTYPE &&
309         //   Type != ELF::STT_OBJECT &&
310         //   Type != ELF::STT_FUNC    &&
311         //   Type != ELF::STT_SECTION &&
312         //   Type != ELF::STT_COMMON) {
313         //     continue;
314         //   }
315         std::pair<Linkage, Scope> bindings;
316         auto Name = SymRef.getName(*StringTable);
317         // I am not sure on If this is going to hold as an invariant. Revisit.
318         if (!Name)
319           return Name.takeError();
320         // TODO: weak and hidden
321         if (SymRef.isExternal())
322           bindings = {Linkage::Strong, Scope::Default};
323         else
324           bindings = {Linkage::Strong, Scope::Local};
325
326         if (SymRef.isDefined() &&
327             (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) {
328
329           auto DefinedSection = Obj.getSection(SymRef.st_shndx);
330           if (!DefinedSection)
331             return DefinedSection.takeError();
332           auto sectName = Obj.getSectionName(*DefinedSection);
333           if (!sectName)
334             return Name.takeError();
335
336           auto JitSection = G->findSectionByName(*sectName);
337           if (!JitSection)
338             return make_error<llvm::StringError>(
339                 "Could not find a section", llvm::inconvertibleErrorCode());
340           auto bs = JitSection->blocks();
341           if (bs.empty())
342             return make_error<llvm::StringError>(
343                 "Section has no block", llvm::inconvertibleErrorCode());
344
345           auto B = *bs.begin();
346           LLVM_DEBUG({ dbgs() << "  " << *Name << ": "; });
347
348           auto &S = G->addDefinedSymbol(
349               *B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first,
350               bindings.second, SymRef.getType() == ELF::STT_FUNC, false);
351           JITSymbolTable[SymRef.st_shndx] = &S;
352         }
353         //TODO: The following has to be implmented.
354         // leaving commented out to save time for future patchs
355         /*
356           G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size,
357           Linkage::Strong, Scope::Default, false);
358
359           if(SymRef.isCommon()) {
360             G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0, 0,
361           SymRef.getValue(), false);
362           }
363
364
365           //G->addExternalSymbol(*Name, SymRef.st_size, Linkage::Strong);
366   */
367       }
368     }
369     return Error::success();
370   }
371
372 public:
373   ELFLinkGraphBuilder_x86_64(std::string filename,
374                              const object::ELFFile<object::ELF64LE> &Obj)
375       : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
376                                       getEndianness(Obj))),
377         Obj(Obj) {}
378
379   Expected<std::unique_ptr<LinkGraph>> buildGraph() {
380     // Sanity check: we only operate on relocatable objects.
381     if (!isRelocatable())
382       return make_error<JITLinkError>("Object is not a relocatable ELF");
383
384     auto Secs = Obj.sections();
385
386     if (!Secs) {
387       return Secs.takeError();
388     }
389     sections = *Secs;
390
391     if (auto Err = createNormalizedSections())
392       return std::move(Err);
393
394     if (auto Err = createNormalizedSymbols())
395       return std::move(Err);
396
397     if (auto Err = graphifyRegularSymbols())
398       return std::move(Err);
399
400     if (auto Err = addRelocations())
401       return std::move(Err);
402
403     return std::move(G);
404   }
405 };
406
407 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
408   friend class JITLinker<ELFJITLinker_x86_64>;
409
410 public:
411   ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
412                       PassConfiguration PassConfig)
413       : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
414
415 private:
416   StringRef getEdgeKindName(Edge::Kind R) const override { return StringRef(); }
417
418   Expected<std::unique_ptr<LinkGraph>>
419   buildGraph(MemoryBufferRef ObjBuffer) override {
420     auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
421     if (!ELFObj)
422       return ELFObj.takeError();
423
424     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
425     std::string fileName(ELFObj->get()->getFileName());
426     return ELFLinkGraphBuilder_x86_64(std::move(fileName),
427                                       *ELFObjFile.getELFFile())
428         .buildGraph();
429   }
430
431   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
432     using namespace ELF_x86_64_Edges;
433     char *FixupPtr = BlockWorkingMem + E.getOffset();
434     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
435     switch (E.getKind()) {
436
437     case ELFX86RelocationKind::PCRel32:
438       int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
439       // verify
440       *(support::little32_t *)FixupPtr = Value;
441       break;
442     }
443     return Error::success();
444   }
445 };
446
447 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
448   PassConfiguration Config;
449   Triple TT("x86_64-linux");
450   // Construct a JITLinker and run the link function.
451   // Add a mark-live pass.
452   if (auto MarkLive = Ctx->getMarkLivePass(TT))
453     Config.PrePrunePasses.push_back(std::move(MarkLive));
454   else
455     Config.PrePrunePasses.push_back(markAllSymbolsLive);
456
457   if (auto Err = Ctx->modifyPassConfig(TT, Config))
458     return Ctx->notifyFailed(std::move(Err));
459
460   ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
461 }
462 } // end namespace jitlink
463 } // end namespace llvm