1 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/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 // MachO/x86-64 jit-link implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
14 
15 #include "BasicGOTAndStubsBuilder.h"
16 #include "MachOLinkGraphBuilder.h"
17 
18 #define DEBUG_TYPE "jitlink"
19 
20 using namespace llvm;
21 using namespace llvm::jitlink;
22 using namespace llvm::jitlink::MachO_x86_64_Edges;
23 
24 namespace {
25 
26 class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
27 public:
MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile & Obj)28   MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
29       : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin")) {}
30 
31 private:
32   static Expected<MachOX86RelocationKind>
getRelocationKind(const MachO::relocation_info & RI)33   getRelocationKind(const MachO::relocation_info &RI) {
34     switch (RI.r_type) {
35     case MachO::X86_64_RELOC_UNSIGNED:
36       if (!RI.r_pcrel) {
37         if (RI.r_length == 3)
38           return RI.r_extern ? Pointer64 : Pointer64Anon;
39         else if (RI.r_extern && RI.r_length == 2)
40           return Pointer32;
41       }
42       break;
43     case MachO::X86_64_RELOC_SIGNED:
44       if (RI.r_pcrel && RI.r_length == 2)
45         return RI.r_extern ? PCRel32 : PCRel32Anon;
46       break;
47     case MachO::X86_64_RELOC_BRANCH:
48       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
49         return Branch32;
50       break;
51     case MachO::X86_64_RELOC_GOT_LOAD:
52       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
53         return PCRel32GOTLoad;
54       break;
55     case MachO::X86_64_RELOC_GOT:
56       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
57         return PCRel32GOT;
58       break;
59     case MachO::X86_64_RELOC_SUBTRACTOR:
60       // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
61       // Initially represent SUBTRACTOR relocations with 'Delta<W>'. They may
62       // be turned into NegDelta<W> by parsePairRelocation.
63       if (!RI.r_pcrel && RI.r_extern) {
64         if (RI.r_length == 2)
65           return Delta32;
66         else if (RI.r_length == 3)
67           return Delta64;
68       }
69       break;
70     case MachO::X86_64_RELOC_SIGNED_1:
71       if (RI.r_pcrel && RI.r_length == 2)
72         return RI.r_extern ? PCRel32Minus1 : PCRel32Minus1Anon;
73       break;
74     case MachO::X86_64_RELOC_SIGNED_2:
75       if (RI.r_pcrel && RI.r_length == 2)
76         return RI.r_extern ? PCRel32Minus2 : PCRel32Minus2Anon;
77       break;
78     case MachO::X86_64_RELOC_SIGNED_4:
79       if (RI.r_pcrel && RI.r_length == 2)
80         return RI.r_extern ? PCRel32Minus4 : PCRel32Minus4Anon;
81       break;
82     case MachO::X86_64_RELOC_TLV:
83       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
84         return PCRel32TLV;
85       break;
86     }
87 
88     return make_error<JITLinkError>(
89         "Unsupported x86-64 relocation: address=" +
90         formatv("{0:x8}", RI.r_address) +
91         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
92         ", kind=" + formatv("{0:x1}", RI.r_type) +
93         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
94         ", extern=" + (RI.r_extern ? "true" : "false") +
95         ", length=" + formatv("{0:d}", RI.r_length));
96   }
97 
98   using PairRelocInfo = std::tuple<MachOX86RelocationKind, Symbol *, uint64_t>;
99 
100   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
101   // returns the edge kind and addend to be used.
102   Expected<PairRelocInfo>
parsePairRelocation(Block & BlockToFix,Edge::Kind SubtractorKind,const MachO::relocation_info & SubRI,JITTargetAddress FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)103   parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
104                       const MachO::relocation_info &SubRI,
105                       JITTargetAddress FixupAddress, const char *FixupContent,
106                       object::relocation_iterator &UnsignedRelItr,
107                       object::relocation_iterator &RelEnd) {
108     using namespace support;
109 
110     assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
111             (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
112            "Subtractor kind should match length");
113     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
114     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
115 
116     if (UnsignedRelItr == RelEnd)
117       return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
118                                       "UNSIGNED relocation");
119 
120     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
121 
122     if (SubRI.r_address != UnsignedRI.r_address)
123       return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
124                                       "point to different addresses");
125 
126     if (SubRI.r_length != UnsignedRI.r_length)
127       return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
128                                       "UNSIGNED reloc must match");
129 
130     Symbol *FromSymbol;
131     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
132       FromSymbol = FromSymbolOrErr->GraphSymbol;
133     else
134       return FromSymbolOrErr.takeError();
135 
136     // Read the current fixup value.
137     uint64_t FixupValue = 0;
138     if (SubRI.r_length == 3)
139       FixupValue = *(const little64_t *)FixupContent;
140     else
141       FixupValue = *(const little32_t *)FixupContent;
142 
143     // Find 'ToSymbol' using symbol number or address, depending on whether the
144     // paired UNSIGNED relocation is extern.
145     Symbol *ToSymbol = nullptr;
146     if (UnsignedRI.r_extern) {
147       // Find target symbol by symbol index.
148       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
149         ToSymbol = ToSymbolOrErr->GraphSymbol;
150       else
151         return ToSymbolOrErr.takeError();
152     } else {
153       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
154       if (!ToSymbolSec)
155         return ToSymbolSec.takeError();
156       ToSymbol = getSymbolByAddress(ToSymbolSec->Address);
157       assert(ToSymbol && "No symbol for section");
158       FixupValue -= ToSymbol->getAddress();
159     }
160 
161     MachOX86RelocationKind DeltaKind;
162     Symbol *TargetSymbol;
163     uint64_t Addend;
164     if (&BlockToFix == &FromSymbol->getAddressable()) {
165       TargetSymbol = ToSymbol;
166       DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
167       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
168       // FIXME: handle extern 'from'.
169     } else if (&BlockToFix == &ToSymbol->getAddressable()) {
170       TargetSymbol = FromSymbol;
171       DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
172       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
173     } else {
174       // BlockToFix was neither FromSymbol nor ToSymbol.
175       return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
176                                       "either 'A' or 'B' (or a symbol in one "
177                                       "of their alt-entry chains)");
178     }
179 
180     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
181   }
182 
addRelocations()183   Error addRelocations() override {
184     using namespace support;
185     auto &Obj = getObject();
186 
187     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
188 
189     for (auto &S : Obj.sections()) {
190 
191       JITTargetAddress SectionAddress = S.getAddress();
192 
193       // Skip relocations virtual sections.
194       if (S.isVirtual()) {
195         if (S.relocation_begin() != S.relocation_end())
196           return make_error<JITLinkError>("Virtual section contains "
197                                           "relocations");
198         continue;
199       }
200 
201       // Skip relocations for debug symbols.
202       {
203         auto &NSec =
204             getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
205         if (!NSec.GraphSection) {
206           LLVM_DEBUG({
207             dbgs() << "  Skipping relocations for MachO section "
208                    << NSec.SegName << "/" << NSec.SectName
209                    << " which has no associated graph section\n";
210           });
211           continue;
212         }
213       }
214 
215       // Add relocations for section.
216       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
217            RelItr != RelEnd; ++RelItr) {
218 
219         MachO::relocation_info RI = getRelocationInfo(RelItr);
220 
221         // Sanity check the relocation kind.
222         auto Kind = getRelocationKind(RI);
223         if (!Kind)
224           return Kind.takeError();
225 
226         // Find the address of the value to fix up.
227         JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
228 
229         LLVM_DEBUG({
230           auto &NSec =
231               getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
232           dbgs() << "  " << NSec.SectName << " + "
233                  << formatv("{0:x8}", RI.r_address) << ":\n";
234         });
235 
236         // Find the block that the fixup points to.
237         Block *BlockToFix = nullptr;
238         {
239           auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
240           if (!SymbolToFixOrErr)
241             return SymbolToFixOrErr.takeError();
242           BlockToFix = &SymbolToFixOrErr->getBlock();
243         }
244 
245         if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
246             BlockToFix->getAddress() + BlockToFix->getContent().size())
247           return make_error<JITLinkError>(
248               "Relocation extends past end of fixup block");
249 
250         // Get a pointer to the fixup content.
251         const char *FixupContent = BlockToFix->getContent().data() +
252                                    (FixupAddress - BlockToFix->getAddress());
253 
254         // The target symbol and addend will be populated by the switch below.
255         Symbol *TargetSymbol = nullptr;
256         uint64_t Addend = 0;
257 
258         switch (*Kind) {
259         case Branch32:
260         case PCRel32:
261         case PCRel32GOTLoad:
262         case PCRel32GOT:
263           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
264             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
265           else
266             return TargetSymbolOrErr.takeError();
267           Addend = *(const little32_t *)FixupContent;
268           break;
269         case Pointer32:
270           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
271             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
272           else
273             return TargetSymbolOrErr.takeError();
274           Addend = *(const ulittle32_t *)FixupContent;
275           break;
276         case Pointer64:
277           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
278             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
279           else
280             return TargetSymbolOrErr.takeError();
281           Addend = *(const ulittle64_t *)FixupContent;
282           break;
283         case Pointer64Anon: {
284           JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
285           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
286             TargetSymbol = &*TargetSymbolOrErr;
287           else
288             return TargetSymbolOrErr.takeError();
289           Addend = TargetAddress - TargetSymbol->getAddress();
290           break;
291         }
292         case PCRel32Minus1:
293         case PCRel32Minus2:
294         case PCRel32Minus4:
295           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
296             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
297           else
298             return TargetSymbolOrErr.takeError();
299           Addend = *(const little32_t *)FixupContent +
300                    (1 << (*Kind - PCRel32Minus1));
301           break;
302         case PCRel32Anon: {
303           JITTargetAddress TargetAddress =
304               FixupAddress + 4 + *(const little32_t *)FixupContent;
305           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
306             TargetSymbol = &*TargetSymbolOrErr;
307           else
308             return TargetSymbolOrErr.takeError();
309           Addend = TargetAddress - TargetSymbol->getAddress();
310           break;
311         }
312         case PCRel32Minus1Anon:
313         case PCRel32Minus2Anon:
314         case PCRel32Minus4Anon: {
315           JITTargetAddress Delta =
316               static_cast<JITTargetAddress>(1ULL << (*Kind - PCRel32Minus1Anon));
317           JITTargetAddress TargetAddress =
318               FixupAddress + 4 + Delta + *(const little32_t *)FixupContent;
319           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
320             TargetSymbol = &*TargetSymbolOrErr;
321           else
322             return TargetSymbolOrErr.takeError();
323           Addend = TargetAddress - TargetSymbol->getAddress();
324           break;
325         }
326         case Delta32:
327         case Delta64: {
328           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
329           // parsePairRelocation handles the paired reloc, and returns the
330           // edge kind to be used (either Delta32/Delta64, or
331           // NegDelta32/NegDelta64, depending on the direction of the
332           // subtraction) along with the addend.
333           auto PairInfo =
334               parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
335                                   FixupContent, ++RelItr, RelEnd);
336           if (!PairInfo)
337             return PairInfo.takeError();
338           std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
339           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
340           break;
341         }
342         case PCRel32TLV:
343           return make_error<JITLinkError>(
344               "MachO TLV relocations not yet supported");
345         default:
346           llvm_unreachable("Special relocation kind should not appear in "
347                            "mach-o file");
348         }
349 
350         LLVM_DEBUG({
351           dbgs() << "    ";
352           Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
353                   Addend);
354           printEdge(dbgs(), *BlockToFix, GE,
355                     getMachOX86RelocationKindName(*Kind));
356           dbgs() << "\n";
357         });
358         BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
359                             *TargetSymbol, Addend);
360       }
361     }
362     return Error::success();
363   }
364 };
365 
366 class MachO_x86_64_GOTAndStubsBuilder
367     : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> {
368 public:
369   static const uint8_t NullGOTEntryContent[8];
370   static const uint8_t StubContent[6];
371 
MachO_x86_64_GOTAndStubsBuilder(LinkGraph & G)372   MachO_x86_64_GOTAndStubsBuilder(LinkGraph &G)
373       : BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder>(G) {}
374 
isGOTEdge(Edge & E) const375   bool isGOTEdge(Edge &E) const {
376     return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
377   }
378 
createGOTEntry(Symbol & Target)379   Symbol &createGOTEntry(Symbol &Target) {
380     auto &GOTEntryBlock = G.createContentBlock(
381         getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
382     GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
383     return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
384   }
385 
fixGOTEdge(Edge & E,Symbol & GOTEntry)386   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
387     assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
388            "Not a GOT edge?");
389     // If this is a PCRel32GOT then change it to an ordinary PCRel32. If it is
390     // a PCRel32GOTLoad then leave it as-is for now. We will use the kind to
391     // check for GOT optimization opportunities in the
392     // optimizeMachO_x86_64_GOTAndStubs pass below.
393     if (E.getKind() == PCRel32GOT)
394       E.setKind(PCRel32);
395 
396     E.setTarget(GOTEntry);
397     // Leave the edge addend as-is.
398   }
399 
isExternalBranchEdge(Edge & E)400   bool isExternalBranchEdge(Edge &E) {
401     return E.getKind() == Branch32 && !E.getTarget().isDefined();
402   }
403 
createStub(Symbol & Target)404   Symbol &createStub(Symbol &Target) {
405     auto &StubContentBlock =
406         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
407     // Re-use GOT entries for stub targets.
408     auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
409     StubContentBlock.addEdge(PCRel32, 2, GOTEntrySymbol, 0);
410     return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
411   }
412 
fixExternalBranchEdge(Edge & E,Symbol & Stub)413   void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
414     assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
415     assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
416 
417     // Set the edge kind to Branch32ToStub. We will use this to check for stub
418     // optimization opportunities in the optimizeMachO_x86_64_GOTAndStubs pass
419     // below.
420     E.setKind(Branch32ToStub);
421     E.setTarget(Stub);
422   }
423 
424 private:
getGOTSection()425   Section &getGOTSection() {
426     if (!GOTSection)
427       GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
428     return *GOTSection;
429   }
430 
getStubsSection()431   Section &getStubsSection() {
432     if (!StubsSection) {
433       auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
434           sys::Memory::MF_READ | sys::Memory::MF_EXEC);
435       StubsSection = &G.createSection("$__STUBS", StubsProt);
436     }
437     return *StubsSection;
438   }
439 
getGOTEntryBlockContent()440   StringRef getGOTEntryBlockContent() {
441     return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
442                      sizeof(NullGOTEntryContent));
443   }
444 
getStubBlockContent()445   StringRef getStubBlockContent() {
446     return StringRef(reinterpret_cast<const char *>(StubContent),
447                      sizeof(StubContent));
448   }
449 
450   Section *GOTSection = nullptr;
451   Section *StubsSection = nullptr;
452 };
453 
454 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
455     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
456 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
457     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
458 } // namespace
459 
optimizeMachO_x86_64_GOTAndStubs(LinkGraph & G)460 static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) {
461   LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
462 
463   for (auto *B : G.blocks())
464     for (auto &E : B->edges())
465       if (E.getKind() == PCRel32GOTLoad) {
466         assert(E.getOffset() >= 3 && "GOT edge occurs too early in block");
467 
468         // Switch the edge kind to PCRel32: Whether we change the edge target
469         // or not this will be the desired kind.
470         E.setKind(PCRel32);
471 
472         // Optimize GOT references.
473         auto &GOTBlock = E.getTarget().getBlock();
474         assert(GOTBlock.getSize() == G.getPointerSize() &&
475                "GOT entry block should be pointer sized");
476         assert(GOTBlock.edges_size() == 1 &&
477                "GOT entry should only have one outgoing edge");
478 
479         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
480         JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
481         JITTargetAddress TargetAddr = GOTTarget.getAddress();
482 
483         // Check that this is a recognized MOV instruction.
484         // FIXME: Can we assume this?
485         constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b};
486         if (strncmp(B->getContent().data() + E.getOffset() - 3,
487                     reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0)
488           continue;
489 
490         int64_t Displacement = TargetAddr - EdgeAddr + 4;
491         if (Displacement >= std::numeric_limits<int32_t>::min() &&
492             Displacement <= std::numeric_limits<int32_t>::max()) {
493           E.setTarget(GOTTarget);
494           auto *BlockData = reinterpret_cast<uint8_t *>(
495               const_cast<char *>(B->getContent().data()));
496           BlockData[E.getOffset() - 2] = 0x8d;
497           LLVM_DEBUG({
498             dbgs() << "  Replaced GOT load wih LEA:\n    ";
499             printEdge(dbgs(), *B, E,
500                       getMachOX86RelocationKindName(E.getKind()));
501             dbgs() << "\n";
502           });
503         }
504       } else if (E.getKind() == Branch32ToStub) {
505 
506         // Switch the edge kind to PCRel32: Whether we change the edge target
507         // or not this will be the desired kind.
508         E.setKind(Branch32);
509 
510         auto &StubBlock = E.getTarget().getBlock();
511         assert(StubBlock.getSize() ==
512                    sizeof(MachO_x86_64_GOTAndStubsBuilder::StubContent) &&
513                "Stub block should be stub sized");
514         assert(StubBlock.edges_size() == 1 &&
515                "Stub block should only have one outgoing edge");
516 
517         auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
518         assert(GOTBlock.getSize() == G.getPointerSize() &&
519                "GOT block should be pointer sized");
520         assert(GOTBlock.edges_size() == 1 &&
521                "GOT block should only have one outgoing edge");
522 
523         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
524         JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
525         JITTargetAddress TargetAddr = GOTTarget.getAddress();
526 
527         int64_t Displacement = TargetAddr - EdgeAddr + 4;
528         if (Displacement >= std::numeric_limits<int32_t>::min() &&
529             Displacement <= std::numeric_limits<int32_t>::max()) {
530           E.setTarget(GOTTarget);
531           LLVM_DEBUG({
532             dbgs() << "  Replaced stub branch with direct branch:\n    ";
533             printEdge(dbgs(), *B, E,
534                       getMachOX86RelocationKindName(E.getKind()));
535             dbgs() << "\n";
536           });
537         }
538       }
539 
540   return Error::success();
541 }
542 
543 namespace llvm {
544 namespace jitlink {
545 
546 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
547   friend class JITLinker<MachOJITLinker_x86_64>;
548 
549 public:
MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)550   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
551                         std::unique_ptr<LinkGraph> G,
552                         PassConfiguration PassConfig)
553       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
554 
555 private:
getEdgeKindName(Edge::Kind R) const556   StringRef getEdgeKindName(Edge::Kind R) const override {
557     return getMachOX86RelocationKindName(R);
558   }
559 
targetOutOfRangeError(const Block & B,const Edge & E)560   static Error targetOutOfRangeError(const Block &B, const Edge &E) {
561     std::string ErrMsg;
562     {
563       raw_string_ostream ErrStream(ErrMsg);
564       ErrStream << "Relocation target out of range: ";
565       printEdge(ErrStream, B, E, getMachOX86RelocationKindName(E.getKind()));
566       ErrStream << "\n";
567     }
568     return make_error<JITLinkError>(std::move(ErrMsg));
569   }
570 
applyFixup(Block & B,const Edge & E,char * BlockWorkingMem) const571   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
572 
573     using namespace support;
574 
575     char *FixupPtr = BlockWorkingMem + E.getOffset();
576     JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
577 
578     switch (E.getKind()) {
579     case Branch32:
580     case PCRel32:
581     case PCRel32Anon: {
582       int64_t Value =
583           E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
584       if (Value < std::numeric_limits<int32_t>::min() ||
585           Value > std::numeric_limits<int32_t>::max())
586         return targetOutOfRangeError(B, E);
587       *(little32_t *)FixupPtr = Value;
588       break;
589     }
590     case Pointer64:
591     case Pointer64Anon: {
592       uint64_t Value = E.getTarget().getAddress() + E.getAddend();
593       *(ulittle64_t *)FixupPtr = Value;
594       break;
595     }
596     case PCRel32Minus1:
597     case PCRel32Minus2:
598     case PCRel32Minus4: {
599       int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1));
600       int64_t Value =
601           E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
602       if (Value < std::numeric_limits<int32_t>::min() ||
603           Value > std::numeric_limits<int32_t>::max())
604         return targetOutOfRangeError(B, E);
605       *(little32_t *)FixupPtr = Value;
606       break;
607     }
608     case PCRel32Minus1Anon:
609     case PCRel32Minus2Anon:
610     case PCRel32Minus4Anon: {
611       int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon));
612       int64_t Value =
613           E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
614       if (Value < std::numeric_limits<int32_t>::min() ||
615           Value > std::numeric_limits<int32_t>::max())
616         return targetOutOfRangeError(B, E);
617       *(little32_t *)FixupPtr = Value;
618       break;
619     }
620     case Delta32:
621     case Delta64:
622     case NegDelta32:
623     case NegDelta64: {
624       int64_t Value;
625       if (E.getKind() == Delta32 || E.getKind() == Delta64)
626         Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
627       else
628         Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
629 
630       if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
631         if (Value < std::numeric_limits<int32_t>::min() ||
632             Value > std::numeric_limits<int32_t>::max())
633           return targetOutOfRangeError(B, E);
634         *(little32_t *)FixupPtr = Value;
635       } else
636         *(little64_t *)FixupPtr = Value;
637       break;
638     }
639     case Pointer32: {
640       uint64_t Value = E.getTarget().getAddress() + E.getAddend();
641       if (Value > std::numeric_limits<uint32_t>::max())
642         return targetOutOfRangeError(B, E);
643       *(ulittle32_t *)FixupPtr = Value;
644       break;
645     }
646     default:
647       llvm_unreachable("Unrecognized edge kind");
648     }
649 
650     return Error::success();
651   }
652 
653   uint64_t NullValue = 0;
654 };
655 
656 Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer)657 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
658   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
659   if (!MachOObj)
660     return MachOObj.takeError();
661   return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
662 }
663 
link_MachO_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)664 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
665                        std::unique_ptr<JITLinkContext> Ctx) {
666 
667   PassConfiguration Config;
668 
669   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
670     // Add eh-frame passses.
671     Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame"));
672     Config.PrePrunePasses.push_back(EHFrameEdgeFixer(
673         "__eh_frame", G->getPointerSize(), Delta64, Delta32, NegDelta32));
674 
675     // Add a mark-live pass.
676     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
677       Config.PrePrunePasses.push_back(std::move(MarkLive));
678     else
679       Config.PrePrunePasses.push_back(markAllSymbolsLive);
680 
681     // Add an in-place GOT/Stubs pass.
682     Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
683       MachO_x86_64_GOTAndStubsBuilder(G).run();
684       return Error::success();
685     });
686 
687     // Add GOT/Stubs optimizer pass.
688     Config.PreFixupPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);
689   }
690 
691   if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
692     return Ctx->notifyFailed(std::move(Err));
693 
694   // Construct a JITLinker and run the link function.
695   MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
696 }
697 
getMachOX86RelocationKindName(Edge::Kind R)698 StringRef getMachOX86RelocationKindName(Edge::Kind R) {
699   switch (R) {
700   case Branch32:
701     return "Branch32";
702   case Branch32ToStub:
703     return "Branch32ToStub";
704   case Pointer32:
705     return "Pointer32";
706   case Pointer64:
707     return "Pointer64";
708   case Pointer64Anon:
709     return "Pointer64Anon";
710   case PCRel32:
711     return "PCRel32";
712   case PCRel32Minus1:
713     return "PCRel32Minus1";
714   case PCRel32Minus2:
715     return "PCRel32Minus2";
716   case PCRel32Minus4:
717     return "PCRel32Minus4";
718   case PCRel32Anon:
719     return "PCRel32Anon";
720   case PCRel32Minus1Anon:
721     return "PCRel32Minus1Anon";
722   case PCRel32Minus2Anon:
723     return "PCRel32Minus2Anon";
724   case PCRel32Minus4Anon:
725     return "PCRel32Minus4Anon";
726   case PCRel32GOTLoad:
727     return "PCRel32GOTLoad";
728   case PCRel32GOT:
729     return "PCRel32GOT";
730   case PCRel32TLV:
731     return "PCRel32TLV";
732   case Delta32:
733     return "Delta32";
734   case Delta64:
735     return "Delta64";
736   case NegDelta32:
737     return "NegDelta32";
738   case NegDelta64:
739     return "NegDelta64";
740   default:
741     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
742   }
743 }
744 
745 } // end namespace jitlink
746 } // end namespace llvm
747