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