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 // This should become a template as the ELFFile is so a lot of this could become
28 // generic
29 class ELFLinkGraphBuilder_x86_64 {
30 
31 private:
32   Section *CommonSection = nullptr;
33   Section &getCommonSection() {
34     if (!CommonSection) {
35       auto Prot = static_cast<sys::Memory::ProtectionFlags>(
36           sys::Memory::MF_READ | sys::Memory::MF_WRITE);
37       CommonSection = &G->createSection(CommonSectionName, Prot);
38     }
39     return *CommonSection;
40   }
41 
42   std::unique_ptr<LinkGraph> G;
43   // This could be a template
44   const object::ELFFile<object::ELF64LE> &Obj;
45   object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections;
46 
47   bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; }
48 
49   support::endianness
50   getEndianness(const object::ELFFile<object::ELF64LE> &Obj) {
51     return Obj.isLE() ? support::little : support::big;
52   }
53 
54   // This could also just become part of a template
55   unsigned getPointerSize(const object::ELFFile<object::ELF64LE> &Obj) {
56     return Obj.getHeader()->getFileClass() == ELF::ELFCLASS64 ? 8 : 4;
57   }
58 
59   // We don't technically need this right now
60   // But for now going to keep it as it helps me to debug things
61 
62   Error createNormalizedSymbols() {
63     LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");
64 
65     for (auto SecRef : sections) {
66       if (SecRef.sh_type != ELF::SHT_SYMTAB &&
67           SecRef.sh_type != ELF::SHT_DYNSYM)
68         continue;
69 
70       auto Symbols = Obj.symbols(&SecRef);
71       // TODO: Currently I use this function to test things
72       // I also want to leave it to see if its common between MACH and elf
73       // so for now I just want to continue even if there is an error
74       if (errorToBool(Symbols.takeError()))
75         continue;
76 
77       auto StrTabSec = Obj.getSection(SecRef.sh_link);
78       if (!StrTabSec)
79         return StrTabSec.takeError();
80       auto StringTable = Obj.getStringTable(*StrTabSec);
81       if (!StringTable)
82         return StringTable.takeError();
83 
84       for (auto SymRef : *Symbols) {
85         Optional<StringRef> Name;
86         unsigned char Binding;
87         uint64_t Value;
88         uint64_t Size = 0;
89 
90         // FIXME: Read size.
91         (void)Size;
92 
93         if (auto NameOrErr = SymRef.getName(*StringTable)) {
94           Name = *NameOrErr;
95         } else {
96           return NameOrErr.takeError();
97         }
98         Binding = SymRef.getBinding();
99         Value = SymRef.getValue();
100         LLVM_DEBUG({
101           dbgs() << "  ";
102           if (!Name)
103             dbgs() << "<anonymous symbol>";
104           else
105             dbgs() << *Name;
106           dbgs() << ": value = " << formatv("{0:x16}", Value)
107                  << ", type = " << formatv("{0:x2}", SymRef.getType())
108                  << ", binding = " << Binding
109                  << ", size =" << Size;
110           dbgs() << "\n";
111         });
112       }
113     }
114     return Error::success();
115   }
116 
117   Error createNormalizedSections() {
118     LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");
119     for (auto &SecRef : sections) {
120       auto Name = Obj.getSectionName(&SecRef);
121       if (!Name)
122         return Name.takeError();
123       sys::Memory::ProtectionFlags Prot;
124       if (SecRef.sh_flags & ELF::SHF_EXECINSTR) {
125         Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
126                                                          sys::Memory::MF_EXEC);
127       } else {
128         Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
129                                                          sys::Memory::MF_WRITE);
130       }
131       uint64_t Address = SecRef.sh_addr;
132       uint64_t Size = SecRef.sh_size;
133       uint64_t Flags = SecRef.sh_flags;
134       uint64_t Alignment = SecRef.sh_addralign;
135       const char *Data = nullptr;
136       // TODO: figure out what it is that has 0 size no name and address
137       // 0000-0000
138       if (Size == 0)
139         continue;
140 
141       // FIXME: Use flags.
142       (void)Flags;
143 
144       LLVM_DEBUG({
145         dbgs() << "  " << *Name << ": " << formatv("{0:x16}", Address) << " -- "
146                << formatv("{0:x16}", Address + Size) << ", align: " << Alignment
147                << " Flags:" << Flags << "\n";
148       });
149 
150       if (SecRef.sh_type != ELF::SHT_NOBITS) {
151         // .sections() already checks that the data is not beyond the end of
152         // file
153         auto contents = Obj.getSectionContentsAsArray<char>(&SecRef);
154         if (!contents)
155           return contents.takeError();
156 
157         Data = contents->data();
158         // TODO protection flags.
159         // for now everything is
160         auto &section = G->createSection(*Name, Prot);
161         // Do this here because we have it, but move it into graphify later
162         G->createContentBlock(section, StringRef(Data, Size), Address,
163                               Alignment, 0);
164       }
165     }
166 
167     return Error::success();
168   }
169 
170   Error graphifyRegularSymbols() {
171 
172     // TODO: ELF supports beyond SHN_LORESERVE,
173     // need to perf test how a vector vs map handles those cases
174 
175     std::vector<std::vector<object::ELFFile<object::ELF64LE>::Elf_Shdr_Range *>>
176         SecIndexToSymbols;
177 
178     LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");
179 
180     for (auto SecRef : sections) {
181 
182       if (SecRef.sh_type != ELF::SHT_SYMTAB &&
183           SecRef.sh_type != ELF::SHT_DYNSYM)
184         continue;
185       auto Symbols = Obj.symbols(&SecRef);
186       if (!Symbols)
187         return Symbols.takeError();
188 
189       auto StrTabSec = Obj.getSection(SecRef.sh_link);
190       if (!StrTabSec)
191         return StrTabSec.takeError();
192       auto StringTable = Obj.getStringTable(*StrTabSec);
193       if (!StringTable)
194         return StringTable.takeError();
195       auto Name = Obj.getSectionName(&SecRef);
196       if (!Name)
197         return Name.takeError();
198       auto Section = G->findSectionByName(*Name);
199       if (!Section)
200         return make_error<llvm::StringError>("Could not find a section",
201                                              llvm::inconvertibleErrorCode());
202       // we only have one for now
203       auto blocks = Section->blocks();
204       if (blocks.empty())
205         return make_error<llvm::StringError>("Section has no block",
206                                              llvm::inconvertibleErrorCode());
207 
208       for (auto SymRef : *Symbols) {
209         auto Type = SymRef.getType();
210         if (Type == ELF::STT_NOTYPE || Type == ELF::STT_FILE)
211           continue;
212         // these should do it for now
213         // if(Type != ELF::STT_NOTYPE &&
214         //   Type != ELF::STT_OBJECT &&
215         //   Type != ELF::STT_FUNC    &&
216         //   Type != ELF::STT_SECTION &&
217         //   Type != ELF::STT_COMMON) {
218         //     continue;
219         //   }
220         std::pair<Linkage, Scope> bindings;
221         auto Name = SymRef.getName(*StringTable);
222         // I am not sure on If this is going to hold as an invariant. Revisit.
223         if (!Name)
224           return Name.takeError();
225         // TODO: weak and hidden
226         if (SymRef.isExternal()) {
227           bindings = {Linkage::Strong, Scope::Default};
228         } else {
229           bindings = {Linkage::Strong, Scope::Local};
230         }
231 
232         if (SymRef.isDefined() &&
233             (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) {
234 
235           auto DefinedSection = Obj.getSection(SymRef.st_shndx);
236           if (!DefinedSection)
237             return DefinedSection.takeError();
238           auto sectName = Obj.getSectionName(*DefinedSection);
239           if (!sectName)
240             return Name.takeError();
241 
242           auto JitSection = G->findSectionByName(*sectName);
243           if (!JitSection)
244             return make_error<llvm::StringError>(
245                 "Could not find a section", llvm::inconvertibleErrorCode());
246           auto bs = JitSection->blocks();
247           if (bs.empty())
248             return make_error<llvm::StringError>(
249                 "Section has no block", llvm::inconvertibleErrorCode());
250 
251           auto B = *bs.begin();
252           LLVM_DEBUG({ dbgs() << "  " << *Name << ": "; });
253 
254           G->addDefinedSymbol(*B, SymRef.getValue(), *Name, SymRef.st_size,
255                               bindings.first, bindings.second,
256                               SymRef.getType() == ELF::STT_FUNC, false);
257         }
258         //TODO: The following has to be implmented.
259         // leaving commented out to save time for future patchs
260         /*
261           G->addAbsoluteSymbol(*Name, SymRef.getValue(), SymRef.st_size,
262           Linkage::Strong, Scope::Default, false);
263 
264           if(SymRef.isCommon()) {
265             G->addCommonSymbol(*Name, Scope::Default, getCommonSection(), 0, 0,
266           SymRef.getValue(), false);
267           }
268 
269 
270           //G->addExternalSymbol(*Name, SymRef.st_size, Linkage::Strong);
271   */
272       }
273     }
274     return Error::success();
275   }
276 
277 public:
278   ELFLinkGraphBuilder_x86_64(std::string filename,
279                              const object::ELFFile<object::ELF64LE> &Obj)
280       : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
281                                       getEndianness(Obj))),
282         Obj(Obj) {}
283 
284   Expected<std::unique_ptr<LinkGraph>> buildGraph() {
285     // Sanity check: we only operate on relocatable objects.
286     if (!isRelocatable())
287       return make_error<JITLinkError>("Object is not a relocatable ELF");
288 
289     auto Secs = Obj.sections();
290 
291     if (!Secs) {
292       return Secs.takeError();
293     }
294     sections = *Secs;
295 
296     if (auto Err = createNormalizedSections())
297       return std::move(Err);
298 
299     if (auto Err = createNormalizedSymbols())
300       return std::move(Err);
301 
302     if (auto Err = graphifyRegularSymbols())
303       return std::move(Err);
304 
305     return std::move(G);
306   }
307 };
308 
309 class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
310   friend class JITLinker<ELFJITLinker_x86_64>;
311 
312 public:
313   ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
314                       PassConfiguration PassConfig)
315       : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
316 
317 private:
318   StringRef getEdgeKindName(Edge::Kind R) const override {
319     return getELFX86RelocationKindName(R);
320   }
321 
322   Expected<std::unique_ptr<LinkGraph>>
323   buildGraph(MemoryBufferRef ObjBuffer) override {
324     auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
325     if (!ELFObj)
326       return ELFObj.takeError();
327 
328     auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
329     std::string fileName(ELFObj->get()->getFileName());
330     return ELFLinkGraphBuilder_x86_64(std::move(fileName),
331                                       *ELFObjFile.getELFFile())
332         .buildGraph();
333   }
334 
335   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
336     //TODO: add relocation handling
337     return Error::success();
338   }
339 };
340 
341 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
342   PassConfiguration Config;
343   Triple TT("x86_64-linux");
344   // Construct a JITLinker and run the link function.
345   // Add a mark-live pass.
346   if (auto MarkLive = Ctx->getMarkLivePass(TT))
347     Config.PrePrunePasses.push_back(std::move(MarkLive));
348   else
349     Config.PrePrunePasses.push_back(markAllSymbolsLive);
350 
351   ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
352 }
353 
354 StringRef getELFX86RelocationKindName(Edge::Kind R) {
355   // case R_AMD64_NONE:
356   //   return "None";
357   // case R_AMD64_PC32:
358   // case R_AMD64_GOT32:
359   // case R_AMD64_PLT32,
360   // R_AMD64_COPY,
361   // R_AMD64_GLOB_DAT,
362   // R_AMD64_JUMP_SLOT,
363   // R_AMD64_RELATIVE,
364   // R_AMD64_GOTPCREL,
365   // R_AMD64_32,
366   // R_AMD64_32S,
367   // R_AMD64_16,
368   // R_AMD64_PC16,
369   // R_AMD64_8,
370   // R_AMD64_PC8,
371   // R_AMD64_PC64,
372   // R_AMD64_GOTOFF64,
373   // R_AMD64_GOTPC32,
374   // R_AMD64_SIZE32,
375   // R_AMD64_SIZE64
376   return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
377 }
378 } // end namespace jitlink
379 } // end namespace llvm
380