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     if (&BlockToFix == &FromSymbol->getAddressable()) {
183       TargetSymbol = ToSymbol;
184       DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32;
185       Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
186       // FIXME: handle extern 'from'.
187     } else if (&BlockToFix == &ToSymbol->getAddressable()) {
188       TargetSymbol = FromSymbol;
189       DeltaKind =
190           (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32;
191       Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
192     } else {
193       // BlockToFix was neither FromSymbol nor ToSymbol.
194       return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
195                                       "either 'A' or 'B' (or a symbol in one "
196                                       "of their alt-entry chains)");
197     }
198 
199     return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
200   }
201 
202   Error addRelocations() override {
203     using namespace support;
204     auto &Obj = getObject();
205 
206     LLVM_DEBUG(dbgs() << "Processing relocations:\n");
207 
208     for (const auto &S : Obj.sections()) {
209 
210       orc::ExecutorAddr SectionAddress(S.getAddress());
211 
212       // Skip relocations virtual sections.
213       if (S.isVirtual()) {
214         if (S.relocation_begin() != S.relocation_end())
215           return make_error<JITLinkError>("Virtual section contains "
216                                           "relocations");
217         continue;
218       }
219 
220       auto NSec =
221           findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
222       if (!NSec)
223         return NSec.takeError();
224 
225       // Skip relocations for MachO sections without corresponding graph
226       // sections.
227       {
228         if (!NSec->GraphSection) {
229           LLVM_DEBUG({
230             dbgs() << "  Skipping relocations for MachO section "
231                    << NSec->SegName << "/" << NSec->SectName
232                    << " which has no associated graph section\n";
233           });
234           continue;
235         }
236       }
237 
238       // Add relocations for section.
239       for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
240            RelItr != RelEnd; ++RelItr) {
241 
242         MachO::relocation_info RI = getRelocationInfo(RelItr);
243 
244         // Find the address of the value to fix up.
245         auto FixupAddress = SectionAddress + (uint32_t)RI.r_address;
246 
247         LLVM_DEBUG({
248           dbgs() << "  " << NSec->SectName << " + "
249                  << formatv("{0:x8}", RI.r_address) << ":\n";
250         });
251 
252         // Find the block that the fixup points to.
253         Block *BlockToFix = nullptr;
254         {
255           auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
256           if (!SymbolToFixOrErr)
257             return SymbolToFixOrErr.takeError();
258           BlockToFix = &SymbolToFixOrErr->getBlock();
259         }
260 
261         if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
262             BlockToFix->getAddress() + BlockToFix->getContent().size())
263           return make_error<JITLinkError>(
264               "Relocation extends past end of fixup block");
265 
266         // Get a pointer to the fixup content.
267         const char *FixupContent = BlockToFix->getContent().data() +
268                                    (FixupAddress - BlockToFix->getAddress());
269 
270         size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
271 
272         // The target symbol and addend will be populated by the switch below.
273         Symbol *TargetSymbol = nullptr;
274         uint64_t Addend = 0;
275 
276         // Validate the relocation kind.
277         auto MachORelocKind = getRelocKind(RI);
278         if (!MachORelocKind)
279           return MachORelocKind.takeError();
280 
281         Edge::Kind Kind = Edge::Invalid;
282 
283         switch (*MachORelocKind) {
284         case MachOBranch32:
285           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
286             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
287           else
288             return TargetSymbolOrErr.takeError();
289           Addend = *(const little32_t *)FixupContent;
290           Kind = x86_64::BranchPCRel32;
291           break;
292         case MachOPCRel32:
293           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
294             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
295           else
296             return TargetSymbolOrErr.takeError();
297           Addend = *(const little32_t *)FixupContent - 4;
298           Kind = x86_64::Delta32;
299           break;
300         case MachOPCRel32GOTLoad:
301           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
302             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
303           else
304             return TargetSymbolOrErr.takeError();
305           Addend = *(const little32_t *)FixupContent;
306           Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
307           if (FixupOffset < 3)
308             return make_error<JITLinkError>("GOTLD at invalid offset " +
309                                             formatv("{0}", FixupOffset));
310           break;
311         case MachOPCRel32GOT:
312           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
313             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
314           else
315             return TargetSymbolOrErr.takeError();
316           Addend = *(const little32_t *)FixupContent - 4;
317           Kind = x86_64::RequestGOTAndTransformToDelta32;
318           break;
319         case MachOPCRel32TLV:
320           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
321             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
322           else
323             return TargetSymbolOrErr.takeError();
324           Addend = *(const little32_t *)FixupContent;
325           Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
326           if (FixupOffset < 3)
327             return make_error<JITLinkError>("TLV at invalid offset " +
328                                             formatv("{0}", FixupOffset));
329           break;
330         case MachOPointer32:
331           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
332             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
333           else
334             return TargetSymbolOrErr.takeError();
335           Addend = *(const ulittle32_t *)FixupContent;
336           Kind = x86_64::Pointer32;
337           break;
338         case MachOPointer64:
339           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
340             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
341           else
342             return TargetSymbolOrErr.takeError();
343           Addend = *(const ulittle64_t *)FixupContent;
344           Kind = x86_64::Pointer64;
345           break;
346         case MachOPointer64Anon: {
347           orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
348           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
349           if (!TargetNSec)
350             return TargetNSec.takeError();
351           if (auto TargetSymbolOrErr =
352                   findSymbolByAddress(*TargetNSec, TargetAddress))
353             TargetSymbol = &*TargetSymbolOrErr;
354           else
355             return TargetSymbolOrErr.takeError();
356           Addend = TargetAddress - TargetSymbol->getAddress();
357           Kind = x86_64::Pointer64;
358           break;
359         }
360         case MachOPCRel32Minus1:
361         case MachOPCRel32Minus2:
362         case MachOPCRel32Minus4:
363           if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
364             TargetSymbol = TargetSymbolOrErr->GraphSymbol;
365           else
366             return TargetSymbolOrErr.takeError();
367           Addend = *(const little32_t *)FixupContent - 4;
368           Kind = x86_64::Delta32;
369           break;
370         case MachOPCRel32Anon: {
371           orc::ExecutorAddr TargetAddress(FixupAddress + 4 +
372                                           *(const little32_t *)FixupContent);
373           auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
374           if (!TargetNSec)
375             return TargetNSec.takeError();
376           if (auto TargetSymbolOrErr =
377                   findSymbolByAddress(*TargetNSec, TargetAddress))
378             TargetSymbol = &*TargetSymbolOrErr;
379           else
380             return TargetSymbolOrErr.takeError();
381           Addend = TargetAddress - TargetSymbol->getAddress() - 4;
382           Kind = x86_64::Delta32;
383           break;
384         }
385         case MachOPCRel32Minus1Anon:
386         case MachOPCRel32Minus2Anon:
387         case MachOPCRel32Minus4Anon: {
388           orc::ExecutorAddrDiff Delta =
389               4 + orc::ExecutorAddrDiff(
390                       1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
391           orc::ExecutorAddr TargetAddress =
392               FixupAddress + Delta + *(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() - Delta;
402           Kind = x86_64::Delta32;
403           break;
404         }
405         case MachOSubtractor32:
406         case MachOSubtractor64: {
407           // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
408           // parsePairRelocation handles the paired reloc, and returns the
409           // edge kind to be used (either Delta32/Delta64, or
410           // NegDelta32/NegDelta64, depending on the direction of the
411           // subtraction) along with the addend.
412           auto PairInfo =
413               parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
414                                   FixupAddress, FixupContent, ++RelItr, RelEnd);
415           if (!PairInfo)
416             return PairInfo.takeError();
417           std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
418           assert(TargetSymbol && "No target symbol from parsePairRelocation?");
419           break;
420         }
421         }
422 
423         LLVM_DEBUG({
424           dbgs() << "    ";
425           Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
426                   Addend);
427           printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
428           dbgs() << "\n";
429         });
430         BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
431                             *TargetSymbol, Addend);
432       }
433     }
434     return Error::success();
435   }
436 };
437 
438 Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
439   x86_64::GOTTableManager GOT;
440   x86_64::PLTTableManager PLT(GOT);
441   visitExistingEdges(G, GOT, PLT);
442   return Error::success();
443 }
444 
445 } // namespace
446 
447 namespace llvm {
448 namespace jitlink {
449 
450 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
451   friend class JITLinker<MachOJITLinker_x86_64>;
452 
453 public:
454   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
455                         std::unique_ptr<LinkGraph> G,
456                         PassConfiguration PassConfig)
457       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
458 
459 private:
460   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
461     return x86_64::applyFixup(G, B, E, nullptr);
462   }
463 };
464 
465 Expected<std::unique_ptr<LinkGraph>>
466 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
467   auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
468   if (!MachOObj)
469     return MachOObj.takeError();
470 
471   auto Features = (*MachOObj)->getFeatures();
472   if (!Features)
473     return Features.takeError();
474 
475   return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(*Features))
476       .buildGraph();
477 }
478 
479 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
480                        std::unique_ptr<JITLinkContext> Ctx) {
481 
482   PassConfiguration Config;
483 
484   if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
485     // Add eh-frame passses.
486     Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
487     Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
488 
489     // Add compact unwind splitter pass.
490     Config.PrePrunePasses.push_back(
491         CompactUnwindSplitter("__LD,__compact_unwind"));
492 
493     // Add a mark-live pass.
494     if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
495       Config.PrePrunePasses.push_back(std::move(MarkLive));
496     else
497       Config.PrePrunePasses.push_back(markAllSymbolsLive);
498 
499     // Add an in-place GOT/Stubs pass.
500     Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
501 
502     // Add GOT/Stubs optimizer pass.
503     Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
504   }
505 
506   if (auto Err = Ctx->modifyPassConfig(*G, Config))
507     return Ctx->notifyFailed(std::move(Err));
508 
509   // Construct a JITLinker and run the link function.
510   MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
511 }
512 
513 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
514   return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
515 }
516 
517 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
518   return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
519                           x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32,
520                           x86_64::Delta64, x86_64::NegDelta32);
521 }
522 
523 } // end namespace jitlink
524 } // end namespace llvm
525