xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
15 
16 #include "MachOLinkGraphBuilder.h"
17 #include "PerGraphGOTAndPLTStubsBuilder.h"
18 
19 #define DEBUG_TYPE "jitlink"
20 
21 using namespace llvm;
22 using namespace llvm::jitlink;
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                               x86_64::getEdgeKindName) {}
31 
32 private:
33   enum MachONormalizedRelocationType : unsigned {
34     MachOBranch32,
35     MachOPointer32,
36     MachOPointer64,
37     MachOPointer64Anon,
38     MachOPCRel32,
39     MachOPCRel32Minus1,
40     MachOPCRel32Minus2,
41     MachOPCRel32Minus4,
42     MachOPCRel32Anon,
43     MachOPCRel32Minus1Anon,
44     MachOPCRel32Minus2Anon,
45     MachOPCRel32Minus4Anon,
46     MachOPCRel32GOTLoad,
47     MachOPCRel32GOT,
48     MachOPCRel32TLV,
49     MachOSubtractor32,
50     MachOSubtractor64,
51   };
52 
53   static Expected<MachONormalizedRelocationType>
getRelocKind(const MachO::relocation_info & RI)54   getRelocKind(const MachO::relocation_info &RI) {
55     switch (RI.r_type) {
56     case MachO::X86_64_RELOC_UNSIGNED:
57       if (!RI.r_pcrel) {
58         if (RI.r_length == 3)
59           return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
60         else if (RI.r_extern && RI.r_length == 2)
61           return MachOPointer32;
62       }
63       break;
64     case MachO::X86_64_RELOC_SIGNED:
65       if (RI.r_pcrel && RI.r_length == 2)
66         return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon;
67       break;
68     case MachO::X86_64_RELOC_BRANCH:
69       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
70         return MachOBranch32;
71       break;
72     case MachO::X86_64_RELOC_GOT_LOAD:
73       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
74         return MachOPCRel32GOTLoad;
75       break;
76     case MachO::X86_64_RELOC_GOT:
77       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
78         return MachOPCRel32GOT;
79       break;
80     case MachO::X86_64_RELOC_SUBTRACTOR:
81       if (!RI.r_pcrel && RI.r_extern) {
82         if (RI.r_length == 2)
83           return MachOSubtractor32;
84         else if (RI.r_length == 3)
85           return MachOSubtractor64;
86       }
87       break;
88     case MachO::X86_64_RELOC_SIGNED_1:
89       if (RI.r_pcrel && RI.r_length == 2)
90         return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon;
91       break;
92     case MachO::X86_64_RELOC_SIGNED_2:
93       if (RI.r_pcrel && RI.r_length == 2)
94         return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon;
95       break;
96     case MachO::X86_64_RELOC_SIGNED_4:
97       if (RI.r_pcrel && RI.r_length == 2)
98         return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon;
99       break;
100     case MachO::X86_64_RELOC_TLV:
101       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
102         return MachOPCRel32TLV;
103       break;
104     }
105 
106     return make_error<JITLinkError>(
107         "Unsupported x86-64 relocation: address=" +
108         formatv("{0:x8}", RI.r_address) +
109         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
110         ", kind=" + formatv("{0:x1}", RI.r_type) +
111         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
112         ", extern=" + (RI.r_extern ? "true" : "false") +
113         ", length=" + formatv("{0:d}", RI.r_length));
114   }
115 
116   using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
117 
118   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
119   // returns the edge kind and addend to be used.
parsePairRelocation(Block & BlockToFix,MachONormalizedRelocationType SubtractorKind,const MachO::relocation_info & SubRI,JITTargetAddress FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)120   Expected<PairRelocInfo> parsePairRelocation(
121       Block &BlockToFix, MachONormalizedRelocationType SubtractorKind,
122       const MachO::relocation_info &SubRI, JITTargetAddress FixupAddress,
123       const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
124       object::relocation_iterator &RelEnd) {
125     using namespace support;
126 
127     assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) ||
128             (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) &&
129            "Subtractor kind should match length");
130     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
131     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
132 
133     if (UnsignedRelItr == RelEnd)
134       return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
135                                       "UNSIGNED relocation");
136 
137     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
138 
139     if (SubRI.r_address != UnsignedRI.r_address)
140       return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
141                                       "point to different addresses");
142 
143     if (SubRI.r_length != UnsignedRI.r_length)
144       return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
145                                       "UNSIGNED reloc must match");
146 
147     Symbol *FromSymbol;
148     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
149       FromSymbol = FromSymbolOrErr->GraphSymbol;
150     else
151       return FromSymbolOrErr.takeError();
152 
153     // Read the current fixup value.
154     uint64_t FixupValue = 0;
155     if (SubRI.r_length == 3)
156       FixupValue = *(const little64_t *)FixupContent;
157     else
158       FixupValue = *(const little32_t *)FixupContent;
159 
160     // Find 'ToSymbol' using symbol number or address, depending on whether the
161     // paired UNSIGNED relocation is extern.
162     Symbol *ToSymbol = nullptr;
163     if (UnsignedRI.r_extern) {
164       // Find target symbol by symbol index.
165       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
166         ToSymbol = ToSymbolOrErr->GraphSymbol;
167       else
168         return ToSymbolOrErr.takeError();
169     } else {
170       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
171       if (!ToSymbolSec)
172         return ToSymbolSec.takeError();
173       ToSymbol = getSymbolByAddress(ToSymbolSec->Address);
174       assert(ToSymbol && "No symbol for section");
175       FixupValue -= ToSymbol->getAddress();
176     }
177 
178     Edge::Kind DeltaKind;
179     Symbol *TargetSymbol;
180     uint64_t Addend;
181     if (&BlockToFix == &FromSymbol->getAddressable()) {
182       TargetSymbol = ToSymbol;
183       DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32;
184       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
185       // FIXME: handle extern 'from'.
186     } else if (&BlockToFix == &ToSymbol->getAddressable()) {
187       TargetSymbol = FromSymbol;
188       DeltaKind =
189           (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32;
190       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
191     } else {
192       // BlockToFix was neither FromSymbol nor ToSymbol.
193       return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
194                                       "either 'A' or 'B' (or a symbol in one "
195                                       "of their alt-entry chains)");
196     }
197 
198     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
199   }
200 
addRelocations()201   Error addRelocations() override {
202     using namespace support;
203     auto &Obj = getObject();
204 
205     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
206 
207     for (auto &S : Obj.sections()) {
208 
209       JITTargetAddress SectionAddress = S.getAddress();
210 
211       // Skip relocations virtual sections.
212       if (S.isVirtual()) {
213         if (S.relocation_begin() != S.relocation_end())
214           return make_error<JITLinkError>("Virtual section contains "
215                                           "relocations");
216         continue;
217       }
218 
219       // Skip relocations for debug symbols.
220       {
221         auto &NSec =
222             getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
223         if (!NSec.GraphSection) {
224           LLVM_DEBUG({
225             dbgs() << "  Skipping relocations for MachO section "
226                    << NSec.SegName << "/" << NSec.SectName
227                    << " which has no associated graph section\n";
228           });
229           continue;
230         }
231       }
232 
233       // Add relocations for section.
234       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
235            RelItr != RelEnd; ++RelItr) {
236 
237         MachO::relocation_info RI = getRelocationInfo(RelItr);
238 
239         // Find the address of the value to fix up.
240         JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
241 
242         LLVM_DEBUG({
243           auto &NSec =
244               getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
245           dbgs() << "  " << NSec.SectName << " + "
246                  << formatv("{0:x8}", RI.r_address) << ":\n";
247         });
248 
249         // Find the block that the fixup points to.
250         Block *BlockToFix = nullptr;
251         {
252           auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
253           if (!SymbolToFixOrErr)
254             return SymbolToFixOrErr.takeError();
255           BlockToFix = &SymbolToFixOrErr->getBlock();
256         }
257 
258         if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
259             BlockToFix->getAddress() + BlockToFix->getContent().size())
260           return make_error<JITLinkError>(
261               "Relocation extends past end of fixup block");
262 
263         // Get a pointer to the fixup content.
264         const char *FixupContent = BlockToFix->getContent().data() +
265                                    (FixupAddress - BlockToFix->getAddress());
266 
267         size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
268 
269         // The target symbol and addend will be populated by the switch below.
270         Symbol *TargetSymbol = nullptr;
271         uint64_t Addend = 0;
272 
273         // Sanity check the relocation kind.
274         auto MachORelocKind = getRelocKind(RI);
275         if (!MachORelocKind)
276           return MachORelocKind.takeError();
277 
278         Edge::Kind Kind = Edge::Invalid;
279 
280         switch (*MachORelocKind) {
281         case MachOBranch32:
282           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
283             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
284           else
285             return TargetSymbolOrErr.takeError();
286           Addend = *(const little32_t *)FixupContent;
287           Kind = x86_64::BranchPCRel32;
288           break;
289         case MachOPCRel32:
290           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
291             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
292           else
293             return TargetSymbolOrErr.takeError();
294           Addend = *(const little32_t *)FixupContent - 4;
295           Kind = x86_64::Delta32;
296           break;
297         case MachOPCRel32GOTLoad:
298           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
299             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
300           else
301             return TargetSymbolOrErr.takeError();
302           Addend = *(const little32_t *)FixupContent;
303           Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable;
304           if (FixupOffset < 3)
305             return make_error<JITLinkError>("GOTLD at invalid offset " +
306                                             formatv("{0}", FixupOffset));
307           break;
308         case MachOPCRel32GOT:
309           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
310             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
311           else
312             return TargetSymbolOrErr.takeError();
313           Addend = *(const little32_t *)FixupContent - 4;
314           Kind = x86_64::RequestGOTAndTransformToDelta32;
315           break;
316         case MachOPointer32:
317           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
318             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
319           else
320             return TargetSymbolOrErr.takeError();
321           Addend = *(const ulittle32_t *)FixupContent;
322           Kind = x86_64::Pointer32;
323           break;
324         case MachOPointer64:
325           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
326             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
327           else
328             return TargetSymbolOrErr.takeError();
329           Addend = *(const ulittle64_t *)FixupContent;
330           Kind = x86_64::Pointer64;
331           break;
332         case MachOPointer64Anon: {
333           JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
334           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
335             TargetSymbol = &*TargetSymbolOrErr;
336           else
337             return TargetSymbolOrErr.takeError();
338           Addend = TargetAddress - TargetSymbol->getAddress();
339           Kind = x86_64::Pointer64;
340           break;
341         }
342         case MachOPCRel32Minus1:
343         case MachOPCRel32Minus2:
344         case MachOPCRel32Minus4:
345           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
346             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
347           else
348             return TargetSymbolOrErr.takeError();
349           Addend = *(const little32_t *)FixupContent - 4;
350           Kind = x86_64::Delta32;
351           break;
352         case MachOPCRel32Anon: {
353           JITTargetAddress TargetAddress =
354               FixupAddress + 4 + *(const little32_t *)FixupContent;
355           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
356             TargetSymbol = &*TargetSymbolOrErr;
357           else
358             return TargetSymbolOrErr.takeError();
359           Addend = TargetAddress - TargetSymbol->getAddress() - 4;
360           Kind = x86_64::Delta32;
361           break;
362         }
363         case MachOPCRel32Minus1Anon:
364         case MachOPCRel32Minus2Anon:
365         case MachOPCRel32Minus4Anon: {
366           JITTargetAddress Delta =
367               4 + static_cast<JITTargetAddress>(
368                       1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
369           JITTargetAddress TargetAddress =
370               FixupAddress + Delta + *(const little32_t *)FixupContent;
371           if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
372             TargetSymbol = &*TargetSymbolOrErr;
373           else
374             return TargetSymbolOrErr.takeError();
375           Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
376           Kind = x86_64::Delta32;
377           break;
378         }
379         case MachOSubtractor32:
380         case MachOSubtractor64: {
381           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
382           // parsePairRelocation handles the paired reloc, and returns the
383           // edge kind to be used (either Delta32/Delta64, or
384           // NegDelta32/NegDelta64, depending on the direction of the
385           // subtraction) along with the addend.
386           auto PairInfo =
387               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
388                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
389           if (!PairInfo)
390             return PairInfo.takeError();
391           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
392           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
393           break;
394         }
395         case MachOPCRel32TLV:
396           return make_error<JITLinkError>(
397               "MachO TLV relocations not yet supported");
398         }
399 
400         LLVM_DEBUG({
401           dbgs() << "    ";
402           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
403                   Addend);
404           printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
405           dbgs() << "\n";
406         });
407         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
408                             *TargetSymbol, Addend);
409       }
410     }
411     return Error::success();
412   }
413 };
414 
415 class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64
416     : public PerGraphGOTAndPLTStubsBuilder<
417           PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> {
418 public:
419 
420   using PerGraphGOTAndPLTStubsBuilder<
421       PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>::
422       PerGraphGOTAndPLTStubsBuilder;
423 
isGOTEdgeToFix(Edge & E) const424   bool isGOTEdgeToFix(Edge &E) const {
425     return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 ||
426            E.getKind() ==
427                x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable;
428   }
429 
createGOTEntry(Symbol & Target)430   Symbol &createGOTEntry(Symbol &Target) {
431     return x86_64::createAnonymousPointer(G, getGOTSection(), &Target);
432   }
433 
fixGOTEdge(Edge & E,Symbol & GOTEntry)434   void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
435     // Fix the edge kind.
436     switch (E.getKind()) {
437     case x86_64::RequestGOTAndTransformToDelta32:
438       E.setKind(x86_64::Delta32);
439       break;
440     case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
441       E.setKind(x86_64::PCRel32GOTLoadRelaxable);
442       break;
443     default:
444       llvm_unreachable("Not a GOT transform edge");
445     }
446     // Fix the target, leave the addend as-is.
447     E.setTarget(GOTEntry);
448   }
449 
isExternalBranchEdge(Edge & E)450   bool isExternalBranchEdge(Edge &E) {
451     return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal();
452   }
453 
createPLTStub(Symbol & Target)454   Symbol &createPLTStub(Symbol &Target) {
455     return x86_64::createAnonymousPointerJumpStub(G, getStubsSection(),
456                                                   getGOTEntry(Target));
457   }
458 
fixPLTEdge(Edge & E,Symbol & Stub)459   void fixPLTEdge(Edge &E, Symbol &Stub) {
460     assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?");
461     assert(E.getAddend() == 0 &&
462            "BranchPCRel32 edge has unexpected addend value");
463 
464     // Set the edge kind to BranchPCRel32ToPtrJumpStubRelaxable. We will use
465     // this to check for stub optimization opportunities in the
466     // optimizeMachO_x86_64_GOTAndStubs pass below.
467     E.setKind(x86_64::BranchPCRel32ToPtrJumpStubRelaxable);
468     E.setTarget(Stub);
469   }
470 
471 private:
getGOTSection()472   Section &getGOTSection() {
473     if (!GOTSection)
474       GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
475     return *GOTSection;
476   }
477 
getStubsSection()478   Section &getStubsSection() {
479     if (!StubsSection) {
480       auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
481           sys::Memory::MF_READ | sys::Memory::MF_EXEC);
482       StubsSection = &G.createSection("$__STUBS", StubsProt);
483     }
484     return *StubsSection;
485   }
486 
487   Section *GOTSection = nullptr;
488   Section *StubsSection = nullptr;
489 };
490 
491 } // namespace
492 
optimizeMachO_x86_64_GOTAndStubs(LinkGraph & G)493 static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) {
494   LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
495 
496   for (auto *B : G.blocks())
497     for (auto &E : B->edges())
498       if (E.getKind() == x86_64::PCRel32GOTLoadRelaxable) {
499         assert(E.getOffset() >= 3 && "GOT edge occurs too early in block");
500 
501         // Optimize GOT references.
502         auto &GOTBlock = E.getTarget().getBlock();
503         assert(GOTBlock.getSize() == G.getPointerSize() &&
504                "GOT entry block should be pointer sized");
505         assert(GOTBlock.edges_size() == 1 &&
506                "GOT entry should only have one outgoing edge");
507 
508         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
509         JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
510         JITTargetAddress TargetAddr = GOTTarget.getAddress();
511 
512         // Check that this is a recognized MOV instruction.
513         // FIXME: Can we assume this?
514         constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b};
515         if (strncmp(B->getContent().data() + E.getOffset() - 3,
516                     reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0)
517           continue;
518 
519         int64_t Displacement = TargetAddr - EdgeAddr + 4;
520         if (Displacement >= std::numeric_limits<int32_t>::min() &&
521             Displacement <= std::numeric_limits<int32_t>::max()) {
522           E.setTarget(GOTTarget);
523           E.setKind(x86_64::Delta32);
524           E.setAddend(E.getAddend() - 4);
525           auto *BlockData = reinterpret_cast<uint8_t *>(
526               const_cast<char *>(B->getContent().data()));
527           BlockData[E.getOffset() - 2] = 0x8d;
528           LLVM_DEBUG({
529             dbgs() << "  Replaced GOT load wih LEA:\n    ";
530             printEdge(dbgs(), *B, E, x86_64::getEdgeKindName(E.getKind()));
531             dbgs() << "\n";
532           });
533         }
534       } else if (E.getKind() == x86_64::BranchPCRel32ToPtrJumpStubRelaxable) {
535         auto &StubBlock = E.getTarget().getBlock();
536         assert(StubBlock.getSize() == sizeof(x86_64::PointerJumpStubContent) &&
537                "Stub block should be stub sized");
538         assert(StubBlock.edges_size() == 1 &&
539                "Stub block should only have one outgoing edge");
540 
541         auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
542         assert(GOTBlock.getSize() == G.getPointerSize() &&
543                "GOT block should be pointer sized");
544         assert(GOTBlock.edges_size() == 1 &&
545                "GOT block should only have one outgoing edge");
546 
547         auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
548         JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
549         JITTargetAddress TargetAddr = GOTTarget.getAddress();
550 
551         int64_t Displacement = TargetAddr - EdgeAddr + 4;
552         if (Displacement >= std::numeric_limits<int32_t>::min() &&
553             Displacement <= std::numeric_limits<int32_t>::max()) {
554           E.setKind(x86_64::BranchPCRel32);
555           E.setTarget(GOTTarget);
556           LLVM_DEBUG({
557             dbgs() << "  Replaced stub branch with direct branch:\n    ";
558             printEdge(dbgs(), *B, E, x86_64::getEdgeKindName(E.getKind()));
559             dbgs() << "\n";
560           });
561         }
562       }
563 
564   return Error::success();
565 }
566 
567 namespace llvm {
568 namespace jitlink {
569 
570 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
571   friend class JITLinker<MachOJITLinker_x86_64>;
572 
573 public:
MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)574   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
575                         std::unique_ptr<LinkGraph> G,
576                         PassConfiguration PassConfig)
577       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
578 
579 private:
applyFixup(LinkGraph & G,Block & B,const Edge & E,char * BlockWorkingMem) const580   Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
581                    char *BlockWorkingMem) const {
582     return x86_64::applyFixup(G, B, E, BlockWorkingMem);
583   }
584 };
585 
586 Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer)587 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
588   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
589   if (!MachOObj)
590     return MachOObj.takeError();
591   return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
592 }
593 
link_MachO_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)594 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
595                        std::unique_ptr<JITLinkContext> Ctx) {
596 
597   PassConfiguration Config;
598 
599   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
600     // Add eh-frame passses.
601     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
602     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
603 
604     // Add a mark-live pass.
605     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
606       Config.PrePrunePasses.push_back(std::move(MarkLive));
607     else
608       Config.PrePrunePasses.push_back(markAllSymbolsLive);
609 
610     // Add an in-place GOT/Stubs pass.
611     Config.PostPrunePasses.push_back(
612         PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass);
613 
614     // Add GOT/Stubs optimizer pass.
615     Config.PreFixupPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);
616   }
617 
618   if (auto Err = Ctx->modifyPassConfig(*G, Config))
619     return Ctx->notifyFailed(std::move(Err));
620 
621   // Construct a JITLinker and run the link function.
622   MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
623 }
624 
createEHFrameSplitterPass_MachO_x86_64()625 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
626   return EHFrameSplitter("__TEXT,__eh_frame");
627 }
628 
createEHFrameEdgeFixerPass_MachO_x86_64()629 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
630   return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
631                           x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
632 }
633 
634 } // end namespace jitlink
635 } // end namespace llvm
636