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
21using namespace llvm;
22using namespace llvm::jitlink;
23
24namespace {
25
26class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
27public:
28  MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
29      : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"),
30                              x86_64::getEdgeKindName) {}
31
32private:
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 (const 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
437Error 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
446namespace llvm {
447namespace jitlink {
448
449class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
450  friend class JITLinker<MachOJITLinker_x86_64>;
451
452public:
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
458private:
459  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
460    return x86_64::applyFixup(G, B, E, nullptr);
461  }
462};
463
464Expected<std::unique_ptr<LinkGraph>>
465createLinkGraphFromMachOObject_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
472void 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
506LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
507  return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
508}
509
510LinkGraphPassFunction 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