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/DWARFRecordSectionSplitter.h"
15 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
16 
17 #include "MachOLinkGraphBuilder.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:
28   MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj,
29                                SubtargetFeatures Features)
30       : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"),
31                               std::move(Features), x86_64::getEdgeKindName) {}
32 
33 private:
34   enum MachONormalizedRelocationType : unsigned {
35     MachOBranch32,
36     MachOPointer32,
37     MachOPointer64,
38     MachOPointer64Anon,
39     MachOPCRel32,
40     MachOPCRel32Minus1,
41     MachOPCRel32Minus2,
42     MachOPCRel32Minus4,
43     MachOPCRel32Anon,
44     MachOPCRel32Minus1Anon,
45     MachOPCRel32Minus2Anon,
46     MachOPCRel32Minus4Anon,
47     MachOPCRel32GOTLoad,
48     MachOPCRel32GOT,
49     MachOPCRel32TLV,
50     MachOSubtractor32,
51     MachOSubtractor64,
52   };
53 
54   static Expected<MachONormalizedRelocationType>
55   getRelocKind(const MachO::relocation_info &RI) {
56     switch (RI.r_type) {
57     case MachO::X86_64_RELOC_UNSIGNED:
58       if (!RI.r_pcrel) {
59         if (RI.r_length == 3)
60           return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
61         else if (RI.r_extern && RI.r_length == 2)
62           return MachOPointer32;
63       }
64       break;
65     case MachO::X86_64_RELOC_SIGNED:
66       if (RI.r_pcrel && RI.r_length == 2)
67         return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon;
68       break;
69     case MachO::X86_64_RELOC_BRANCH:
70       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
71         return MachOBranch32;
72       break;
73     case MachO::X86_64_RELOC_GOT_LOAD:
74       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
75         return MachOPCRel32GOTLoad;
76       break;
77     case MachO::X86_64_RELOC_GOT:
78       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
79         return MachOPCRel32GOT;
80       break;
81     case MachO::X86_64_RELOC_SUBTRACTOR:
82       if (!RI.r_pcrel && RI.r_extern) {
83         if (RI.r_length == 2)
84           return MachOSubtractor32;
85         else if (RI.r_length == 3)
86           return MachOSubtractor64;
87       }
88       break;
89     case MachO::X86_64_RELOC_SIGNED_1:
90       if (RI.r_pcrel && RI.r_length == 2)
91         return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon;
92       break;
93     case MachO::X86_64_RELOC_SIGNED_2:
94       if (RI.r_pcrel && RI.r_length == 2)
95         return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon;
96       break;
97     case MachO::X86_64_RELOC_SIGNED_4:
98       if (RI.r_pcrel && RI.r_length == 2)
99         return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon;
100       break;
101     case MachO::X86_64_RELOC_TLV:
102       if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
103         return MachOPCRel32TLV;
104       break;
105     }
106 
107     return make_error<JITLinkError>(
108         "Unsupported x86-64 relocation: address=" +
109         formatv("{0:x8}", RI.r_address) +
110         ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
111         ", kind=" + formatv("{0:x1}", RI.r_type) +
112         ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
113         ", extern=" + (RI.r_extern ? "true" : "false") +
114         ", length=" + formatv("{0:d}", RI.r_length));
115   }
116 
117   using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
118 
119   // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
120   // returns the edge kind and addend to be used.
121   Expected<PairRelocInfo> parsePairRelocation(
122       Block &BlockToFix, MachONormalizedRelocationType SubtractorKind,
123       const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress,
124       const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
125       object::relocation_iterator &RelEnd) {
126     using namespace support;
127 
128     assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) ||
129             (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) &&
130            "Subtractor kind should match length");
131     assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
132     assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
133 
134     if (UnsignedRelItr == RelEnd)
135       return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
136                                       "UNSIGNED relocation");
137 
138     auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
139 
140     if (SubRI.r_address != UnsignedRI.r_address)
141       return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
142                                       "point to different addresses");
143 
144     if (SubRI.r_length != UnsignedRI.r_length)
145       return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
146                                       "UNSIGNED reloc must match");
147 
148     Symbol *FromSymbol;
149     if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
150       FromSymbol = FromSymbolOrErr->GraphSymbol;
151     else
152       return FromSymbolOrErr.takeError();
153 
154     // Read the current fixup value.
155     uint64_t FixupValue = 0;
156     if (SubRI.r_length == 3)
157       FixupValue = *(const little64_t *)FixupContent;
158     else
159       FixupValue = *(const little32_t *)FixupContent;
160 
161     // Find 'ToSymbol' using symbol number or address, depending on whether the
162     // paired UNSIGNED relocation is extern.
163     Symbol *ToSymbol = nullptr;
164     if (UnsignedRI.r_extern) {
165       // Find target symbol by symbol index.
166       if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
167         ToSymbol = ToSymbolOrErr->GraphSymbol;
168       else
169         return ToSymbolOrErr.takeError();
170     } else {
171       auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
172       if (!ToSymbolSec)
173         return ToSymbolSec.takeError();
174       ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
175       assert(ToSymbol && "No symbol for section");
176       FixupValue -= ToSymbol->getAddress().getValue();
177     }
178 
179     Edge::Kind DeltaKind;
180     Symbol *TargetSymbol;
181     uint64_t Addend;
182 
183     bool FixingFromSymbol = true;
184     if (&BlockToFix == &FromSymbol->getAddressable()) {
185       if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) {
186         // From and To are symbols in the same block. Decide direction by offset
187         // instead.
188         if (ToSymbol->getAddress() > FixupAddress)
189           FixingFromSymbol = true;
190         else if (FromSymbol->getAddress() > FixupAddress)
191           FixingFromSymbol = false;
192         else
193           FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress();
194       } else
195         FixingFromSymbol = true;
196     } else {
197       if (&BlockToFix == &ToSymbol->getAddressable())
198         FixingFromSymbol = false;
199       else {
200         // BlockToFix was neither FromSymbol nor ToSymbol.
201         return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
202                                         "either 'A' or 'B' (or a symbol in one "
203                                         "of their alt-entry groups)");
204       }
205     }
206 
207     if (FixingFromSymbol) {
208       TargetSymbol = ToSymbol;
209       DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32;
210       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
211       // FIXME: handle extern 'from'.
212     } else {
213       TargetSymbol = FromSymbol;
214       DeltaKind =
215           (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32;
216       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
217     }
218 
219     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
220   }
221 
222   Error addRelocations() override {
223     using namespace support;
224     auto &Obj = getObject();
225 
226     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
227 
228     for (const auto &S : Obj.sections()) {
229 
230       orc::ExecutorAddr SectionAddress(S.getAddress());
231 
232       // Skip relocations virtual sections.
233       if (S.isVirtual()) {
234         if (S.relocation_begin() != S.relocation_end())
235           return make_error<JITLinkError>("Virtual section contains "
236                                           "relocations");
237         continue;
238       }
239 
240       auto NSec =
241           findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
242       if (!NSec)
243         return NSec.takeError();
244 
245       // Skip relocations for MachO sections without corresponding graph
246       // sections.
247       {
248         if (!NSec->GraphSection) {
249           LLVM_DEBUG({
250             dbgs() << "  Skipping relocations for MachO section "
251                    << NSec->SegName << "/" << NSec->SectName
252                    << " which has no associated graph section\n";
253           });
254           continue;
255         }
256       }
257 
258       // Add relocations for section.
259       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
260            RelItr != RelEnd; ++RelItr) {
261 
262         MachO::relocation_info RI = getRelocationInfo(RelItr);
263 
264         // Find the address of the value to fix up.
265         auto FixupAddress = SectionAddress + (uint32_t)RI.r_address;
266 
267         LLVM_DEBUG({
268           dbgs() << "  " << NSec->SectName << " + "
269                  << formatv("{0:x8}", RI.r_address) << ":\n";
270         });
271 
272         // Find the block that the fixup points to.
273         Block *BlockToFix = nullptr;
274         {
275           auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
276           if (!SymbolToFixOrErr)
277             return SymbolToFixOrErr.takeError();
278           BlockToFix = &SymbolToFixOrErr->getBlock();
279         }
280 
281         if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
282             BlockToFix->getAddress() + BlockToFix->getContent().size())
283           return make_error<JITLinkError>(
284               "Relocation extends past end of fixup block");
285 
286         // Get a pointer to the fixup content.
287         const char *FixupContent = BlockToFix->getContent().data() +
288                                    (FixupAddress - BlockToFix->getAddress());
289 
290         size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
291 
292         // The target symbol and addend will be populated by the switch below.
293         Symbol *TargetSymbol = nullptr;
294         uint64_t Addend = 0;
295 
296         // Validate the relocation kind.
297         auto MachORelocKind = getRelocKind(RI);
298         if (!MachORelocKind)
299           return MachORelocKind.takeError();
300 
301         Edge::Kind Kind = Edge::Invalid;
302 
303         switch (*MachORelocKind) {
304         case MachOBranch32:
305           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
306             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
307           else
308             return TargetSymbolOrErr.takeError();
309           Addend = *(const little32_t *)FixupContent;
310           Kind = x86_64::BranchPCRel32;
311           break;
312         case MachOPCRel32:
313           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
314             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
315           else
316             return TargetSymbolOrErr.takeError();
317           Addend = *(const little32_t *)FixupContent - 4;
318           Kind = x86_64::Delta32;
319           break;
320         case MachOPCRel32GOTLoad:
321           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
322             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
323           else
324             return TargetSymbolOrErr.takeError();
325           Addend = *(const little32_t *)FixupContent;
326           Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
327           if (FixupOffset < 3)
328             return make_error<JITLinkError>("GOTLD at invalid offset " +
329                                             formatv("{0}", FixupOffset));
330           break;
331         case MachOPCRel32GOT:
332           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
333             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
334           else
335             return TargetSymbolOrErr.takeError();
336           Addend = *(const little32_t *)FixupContent - 4;
337           Kind = x86_64::RequestGOTAndTransformToDelta32;
338           break;
339         case MachOPCRel32TLV:
340           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
341             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
342           else
343             return TargetSymbolOrErr.takeError();
344           Addend = *(const little32_t *)FixupContent;
345           Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
346           if (FixupOffset < 3)
347             return make_error<JITLinkError>("TLV at invalid offset " +
348                                             formatv("{0}", FixupOffset));
349           break;
350         case MachOPointer32:
351           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
352             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
353           else
354             return TargetSymbolOrErr.takeError();
355           Addend = *(const ulittle32_t *)FixupContent;
356           Kind = x86_64::Pointer32;
357           break;
358         case MachOPointer64:
359           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
360             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
361           else
362             return TargetSymbolOrErr.takeError();
363           Addend = *(const ulittle64_t *)FixupContent;
364           Kind = x86_64::Pointer64;
365           break;
366         case MachOPointer64Anon: {
367           orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
368           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
369           if (!TargetNSec)
370             return TargetNSec.takeError();
371           if (auto TargetSymbolOrErr =
372                   findSymbolByAddress(*TargetNSec, TargetAddress))
373             TargetSymbol = &*TargetSymbolOrErr;
374           else
375             return TargetSymbolOrErr.takeError();
376           Addend = TargetAddress - TargetSymbol->getAddress();
377           Kind = x86_64::Pointer64;
378           break;
379         }
380         case MachOPCRel32Minus1:
381         case MachOPCRel32Minus2:
382         case MachOPCRel32Minus4:
383           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
384             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
385           else
386             return TargetSymbolOrErr.takeError();
387           Addend = *(const little32_t *)FixupContent - 4;
388           Kind = x86_64::Delta32;
389           break;
390         case MachOPCRel32Anon: {
391           orc::ExecutorAddr TargetAddress(FixupAddress + 4 +
392                                           *(const little32_t *)FixupContent);
393           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
394           if (!TargetNSec)
395             return TargetNSec.takeError();
396           if (auto TargetSymbolOrErr =
397                   findSymbolByAddress(*TargetNSec, TargetAddress))
398             TargetSymbol = &*TargetSymbolOrErr;
399           else
400             return TargetSymbolOrErr.takeError();
401           Addend = TargetAddress - TargetSymbol->getAddress() - 4;
402           Kind = x86_64::Delta32;
403           break;
404         }
405         case MachOPCRel32Minus1Anon:
406         case MachOPCRel32Minus2Anon:
407         case MachOPCRel32Minus4Anon: {
408           orc::ExecutorAddrDiff Delta =
409               4 + orc::ExecutorAddrDiff(
410                       1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
411           orc::ExecutorAddr TargetAddress =
412               FixupAddress + Delta + *(const little32_t *)FixupContent;
413           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
414           if (!TargetNSec)
415             return TargetNSec.takeError();
416           if (auto TargetSymbolOrErr =
417                   findSymbolByAddress(*TargetNSec, TargetAddress))
418             TargetSymbol = &*TargetSymbolOrErr;
419           else
420             return TargetSymbolOrErr.takeError();
421           Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
422           Kind = x86_64::Delta32;
423           break;
424         }
425         case MachOSubtractor32:
426         case MachOSubtractor64: {
427           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
428           // parsePairRelocation handles the paired reloc, and returns the
429           // edge kind to be used (either Delta32/Delta64, or
430           // NegDelta32/NegDelta64, depending on the direction of the
431           // subtraction) along with the addend.
432           auto PairInfo =
433               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
434                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
435           if (!PairInfo)
436             return PairInfo.takeError();
437           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
438           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
439           break;
440         }
441         }
442 
443         LLVM_DEBUG({
444           dbgs() << "    ";
445           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
446                   Addend);
447           printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
448           dbgs() << "\n";
449         });
450         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
451                             *TargetSymbol, Addend);
452       }
453     }
454     return Error::success();
455   }
456 };
457 
458 Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
459   x86_64::GOTTableManager GOT;
460   x86_64::PLTTableManager PLT(GOT);
461   visitExistingEdges(G, GOT, PLT);
462   return Error::success();
463 }
464 
465 } // namespace
466 
467 namespace llvm {
468 namespace jitlink {
469 
470 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
471   friend class JITLinker<MachOJITLinker_x86_64>;
472 
473 public:
474   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
475                         std::unique_ptr<LinkGraph> G,
476                         PassConfiguration PassConfig)
477       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
478 
479 private:
480   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
481     return x86_64::applyFixup(G, B, E, nullptr);
482   }
483 };
484 
485 Expected<std::unique_ptr<LinkGraph>>
486 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
487   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
488   if (!MachOObj)
489     return MachOObj.takeError();
490 
491   auto Features = (*MachOObj)->getFeatures();
492   if (!Features)
493     return Features.takeError();
494 
495   return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(*Features))
496       .buildGraph();
497 }
498 
499 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
500                        std::unique_ptr<JITLinkContext> Ctx) {
501 
502   PassConfiguration Config;
503 
504   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
505     // Add eh-frame passes.
506     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
507     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
508 
509     // Add compact unwind splitter pass.
510     Config.PrePrunePasses.push_back(
511         CompactUnwindSplitter("__LD,__compact_unwind"));
512 
513     // Add a mark-live pass.
514     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
515       Config.PrePrunePasses.push_back(std::move(MarkLive));
516     else
517       Config.PrePrunePasses.push_back(markAllSymbolsLive);
518 
519     // Add an in-place GOT/Stubs pass.
520     Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
521 
522     // Add GOT/Stubs optimizer pass.
523     Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
524   }
525 
526   if (auto Err = Ctx->modifyPassConfig(*G, Config))
527     return Ctx->notifyFailed(std::move(Err));
528 
529   // Construct a JITLinker and run the link function.
530   MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
531 }
532 
533 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
534   return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
535 }
536 
537 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
538   return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
539                           x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32,
540                           x86_64::Delta64, x86_64::NegDelta32);
541 }
542 
543 } // end namespace jitlink
544 } // end namespace llvm
545