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