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