10b57cec5SDimitry Andric //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // MachO/x86-64 jit-link implementation.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
1481ad6265SDimitry Andric #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
15fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86_64.h"
160b57cec5SDimitry Andric
17*0fca6ea1SDimitry Andric #include "DefineExternalSectionStartAndEndSymbols.h"
188bcb0991SDimitry Andric #include "MachOLinkGraphBuilder.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink"
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric using namespace llvm::jitlink;
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric namespace {
260b57cec5SDimitry Andric
278bcb0991SDimitry Andric class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
280b57cec5SDimitry Andric public:
MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile & Obj,SubtargetFeatures Features)2906c3fb27SDimitry Andric MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj,
3006c3fb27SDimitry Andric SubtargetFeatures Features)
31fe6060f1SDimitry Andric : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"),
3206c3fb27SDimitry Andric std::move(Features), x86_64::getEdgeKindName) {}
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric private:
35fe6060f1SDimitry Andric enum MachONormalizedRelocationType : unsigned {
36fe6060f1SDimitry Andric MachOBranch32,
37fe6060f1SDimitry Andric MachOPointer32,
38fe6060f1SDimitry Andric MachOPointer64,
39fe6060f1SDimitry Andric MachOPointer64Anon,
40fe6060f1SDimitry Andric MachOPCRel32,
41fe6060f1SDimitry Andric MachOPCRel32Minus1,
42fe6060f1SDimitry Andric MachOPCRel32Minus2,
43fe6060f1SDimitry Andric MachOPCRel32Minus4,
44fe6060f1SDimitry Andric MachOPCRel32Anon,
45fe6060f1SDimitry Andric MachOPCRel32Minus1Anon,
46fe6060f1SDimitry Andric MachOPCRel32Minus2Anon,
47fe6060f1SDimitry Andric MachOPCRel32Minus4Anon,
48fe6060f1SDimitry Andric MachOPCRel32GOTLoad,
49fe6060f1SDimitry Andric MachOPCRel32GOT,
50fe6060f1SDimitry Andric MachOPCRel32TLV,
51fe6060f1SDimitry Andric MachOSubtractor32,
52fe6060f1SDimitry Andric MachOSubtractor64,
53fe6060f1SDimitry Andric };
54fe6060f1SDimitry Andric
55fe6060f1SDimitry Andric static Expected<MachONormalizedRelocationType>
getRelocKind(const MachO::relocation_info & RI)56fe6060f1SDimitry Andric getRelocKind(const MachO::relocation_info &RI) {
570b57cec5SDimitry Andric switch (RI.r_type) {
580b57cec5SDimitry Andric case MachO::X86_64_RELOC_UNSIGNED:
598bcb0991SDimitry Andric if (!RI.r_pcrel) {
608bcb0991SDimitry Andric if (RI.r_length == 3)
61fe6060f1SDimitry Andric return RI.r_extern ? MachOPointer64 : MachOPointer64Anon;
628bcb0991SDimitry Andric else if (RI.r_extern && RI.r_length == 2)
63fe6060f1SDimitry Andric return MachOPointer32;
648bcb0991SDimitry Andric }
650b57cec5SDimitry Andric break;
660b57cec5SDimitry Andric case MachO::X86_64_RELOC_SIGNED:
670b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_length == 2)
68fe6060f1SDimitry Andric return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon;
690b57cec5SDimitry Andric break;
700b57cec5SDimitry Andric case MachO::X86_64_RELOC_BRANCH:
710b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
72fe6060f1SDimitry Andric return MachOBranch32;
730b57cec5SDimitry Andric break;
740b57cec5SDimitry Andric case MachO::X86_64_RELOC_GOT_LOAD:
750b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
76fe6060f1SDimitry Andric return MachOPCRel32GOTLoad;
770b57cec5SDimitry Andric break;
780b57cec5SDimitry Andric case MachO::X86_64_RELOC_GOT:
790b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
80fe6060f1SDimitry Andric return MachOPCRel32GOT;
810b57cec5SDimitry Andric break;
820b57cec5SDimitry Andric case MachO::X86_64_RELOC_SUBTRACTOR:
830b57cec5SDimitry Andric if (!RI.r_pcrel && RI.r_extern) {
840b57cec5SDimitry Andric if (RI.r_length == 2)
85fe6060f1SDimitry Andric return MachOSubtractor32;
860b57cec5SDimitry Andric else if (RI.r_length == 3)
87fe6060f1SDimitry Andric return MachOSubtractor64;
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric break;
900b57cec5SDimitry Andric case MachO::X86_64_RELOC_SIGNED_1:
910b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_length == 2)
92fe6060f1SDimitry Andric return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon;
930b57cec5SDimitry Andric break;
940b57cec5SDimitry Andric case MachO::X86_64_RELOC_SIGNED_2:
950b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_length == 2)
96fe6060f1SDimitry Andric return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon;
970b57cec5SDimitry Andric break;
980b57cec5SDimitry Andric case MachO::X86_64_RELOC_SIGNED_4:
990b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_length == 2)
100fe6060f1SDimitry Andric return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon;
1010b57cec5SDimitry Andric break;
1020b57cec5SDimitry Andric case MachO::X86_64_RELOC_TLV:
1030b57cec5SDimitry Andric if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
104fe6060f1SDimitry Andric return MachOPCRel32TLV;
1050b57cec5SDimitry Andric break;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric return make_error<JITLinkError>(
1090b57cec5SDimitry Andric "Unsupported x86-64 relocation: address=" +
1100b57cec5SDimitry Andric formatv("{0:x8}", RI.r_address) +
1110b57cec5SDimitry Andric ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
1120b57cec5SDimitry Andric ", kind=" + formatv("{0:x1}", RI.r_type) +
1130b57cec5SDimitry Andric ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
1140b57cec5SDimitry Andric ", extern=" + (RI.r_extern ? "true" : "false") +
1150b57cec5SDimitry Andric ", length=" + formatv("{0:d}", RI.r_length));
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
118fe6060f1SDimitry Andric using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
1210b57cec5SDimitry Andric // returns the edge kind and addend to be used.
parsePairRelocation(Block & BlockToFix,MachONormalizedRelocationType SubtractorKind,const MachO::relocation_info & SubRI,orc::ExecutorAddr FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)122fe6060f1SDimitry Andric Expected<PairRelocInfo> parsePairRelocation(
123fe6060f1SDimitry Andric Block &BlockToFix, MachONormalizedRelocationType SubtractorKind,
12404eeddc0SDimitry Andric const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress,
125fe6060f1SDimitry Andric const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
1260b57cec5SDimitry Andric object::relocation_iterator &RelEnd) {
1270b57cec5SDimitry Andric using namespace support;
1280b57cec5SDimitry Andric
129fe6060f1SDimitry Andric assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) ||
130fe6060f1SDimitry Andric (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) &&
1310b57cec5SDimitry Andric "Subtractor kind should match length");
1320b57cec5SDimitry Andric assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
1330b57cec5SDimitry Andric assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric if (UnsignedRelItr == RelEnd)
1360b57cec5SDimitry Andric return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
1370b57cec5SDimitry Andric "UNSIGNED relocation");
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric if (SubRI.r_address != UnsignedRI.r_address)
1420b57cec5SDimitry Andric return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
1430b57cec5SDimitry Andric "point to different addresses");
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric if (SubRI.r_length != UnsignedRI.r_length)
1460b57cec5SDimitry Andric return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired "
1470b57cec5SDimitry Andric "UNSIGNED reloc must match");
1480b57cec5SDimitry Andric
1498bcb0991SDimitry Andric Symbol *FromSymbol;
1508bcb0991SDimitry Andric if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
1518bcb0991SDimitry Andric FromSymbol = FromSymbolOrErr->GraphSymbol;
1528bcb0991SDimitry Andric else
1538bcb0991SDimitry Andric return FromSymbolOrErr.takeError();
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric // Read the current fixup value.
1560b57cec5SDimitry Andric uint64_t FixupValue = 0;
1570b57cec5SDimitry Andric if (SubRI.r_length == 3)
1580b57cec5SDimitry Andric FixupValue = *(const little64_t *)FixupContent;
1590b57cec5SDimitry Andric else
1600b57cec5SDimitry Andric FixupValue = *(const little32_t *)FixupContent;
1610b57cec5SDimitry Andric
1628bcb0991SDimitry Andric // Find 'ToSymbol' using symbol number or address, depending on whether the
1630b57cec5SDimitry Andric // paired UNSIGNED relocation is extern.
1648bcb0991SDimitry Andric Symbol *ToSymbol = nullptr;
1650b57cec5SDimitry Andric if (UnsignedRI.r_extern) {
1668bcb0991SDimitry Andric // Find target symbol by symbol index.
1678bcb0991SDimitry Andric if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
1688bcb0991SDimitry Andric ToSymbol = ToSymbolOrErr->GraphSymbol;
1690b57cec5SDimitry Andric else
1708bcb0991SDimitry Andric return ToSymbolOrErr.takeError();
1710b57cec5SDimitry Andric } else {
172e8d8bef9SDimitry Andric auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1);
173e8d8bef9SDimitry Andric if (!ToSymbolSec)
174e8d8bef9SDimitry Andric return ToSymbolSec.takeError();
175349cc55cSDimitry Andric ToSymbol = getSymbolByAddress(*ToSymbolSec, ToSymbolSec->Address);
176e8d8bef9SDimitry Andric assert(ToSymbol && "No symbol for section");
17704eeddc0SDimitry Andric FixupValue -= ToSymbol->getAddress().getValue();
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
180fe6060f1SDimitry Andric Edge::Kind DeltaKind;
1818bcb0991SDimitry Andric Symbol *TargetSymbol;
1820b57cec5SDimitry Andric uint64_t Addend;
183cb14a3feSDimitry Andric
184cb14a3feSDimitry Andric bool FixingFromSymbol = true;
1858bcb0991SDimitry Andric if (&BlockToFix == &FromSymbol->getAddressable()) {
186cb14a3feSDimitry Andric if (LLVM_UNLIKELY(&BlockToFix == &ToSymbol->getAddressable())) {
187cb14a3feSDimitry Andric // From and To are symbols in the same block. Decide direction by offset
188cb14a3feSDimitry Andric // instead.
189cb14a3feSDimitry Andric if (ToSymbol->getAddress() > FixupAddress)
190cb14a3feSDimitry Andric FixingFromSymbol = true;
191cb14a3feSDimitry Andric else if (FromSymbol->getAddress() > FixupAddress)
192cb14a3feSDimitry Andric FixingFromSymbol = false;
193cb14a3feSDimitry Andric else
194cb14a3feSDimitry Andric FixingFromSymbol = FromSymbol->getAddress() >= ToSymbol->getAddress();
195cb14a3feSDimitry Andric } else
196cb14a3feSDimitry Andric FixingFromSymbol = true;
197cb14a3feSDimitry Andric } else {
198cb14a3feSDimitry Andric if (&BlockToFix == &ToSymbol->getAddressable())
199cb14a3feSDimitry Andric FixingFromSymbol = false;
200cb14a3feSDimitry Andric else {
201cb14a3feSDimitry Andric // BlockToFix was neither FromSymbol nor ToSymbol.
202cb14a3feSDimitry Andric return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
203cb14a3feSDimitry Andric "either 'A' or 'B' (or a symbol in one "
204cb14a3feSDimitry Andric "of their alt-entry groups)");
205cb14a3feSDimitry Andric }
206cb14a3feSDimitry Andric }
207cb14a3feSDimitry Andric
208cb14a3feSDimitry Andric if (FixingFromSymbol) {
2098bcb0991SDimitry Andric TargetSymbol = ToSymbol;
210fe6060f1SDimitry Andric DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32;
2118bcb0991SDimitry Andric Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
2120b57cec5SDimitry Andric // FIXME: handle extern 'from'.
213cb14a3feSDimitry Andric } else {
2148bcb0991SDimitry Andric TargetSymbol = FromSymbol;
215fe6060f1SDimitry Andric DeltaKind =
216fe6060f1SDimitry Andric (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32;
2178bcb0991SDimitry Andric Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric
2208bcb0991SDimitry Andric return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric
addRelocations()2230b57cec5SDimitry Andric Error addRelocations() override {
2240b57cec5SDimitry Andric using namespace support;
2250b57cec5SDimitry Andric auto &Obj = getObject();
2260b57cec5SDimitry Andric
227e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Processing relocations:\n");
228e8d8bef9SDimitry Andric
229bdd1243dSDimitry Andric for (const auto &S : Obj.sections()) {
2300b57cec5SDimitry Andric
23104eeddc0SDimitry Andric orc::ExecutorAddr SectionAddress(S.getAddress());
2320b57cec5SDimitry Andric
2335ffd83dbSDimitry Andric // Skip relocations virtual sections.
2348bcb0991SDimitry Andric if (S.isVirtual()) {
2358bcb0991SDimitry Andric if (S.relocation_begin() != S.relocation_end())
2368bcb0991SDimitry Andric return make_error<JITLinkError>("Virtual section contains "
2378bcb0991SDimitry Andric "relocations");
2388bcb0991SDimitry Andric continue;
2398bcb0991SDimitry Andric }
2408bcb0991SDimitry Andric
241349cc55cSDimitry Andric auto NSec =
242349cc55cSDimitry Andric findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
243349cc55cSDimitry Andric if (!NSec)
244349cc55cSDimitry Andric return NSec.takeError();
245349cc55cSDimitry Andric
246349cc55cSDimitry Andric // Skip relocations for MachO sections without corresponding graph
247349cc55cSDimitry Andric // sections.
2485ffd83dbSDimitry Andric {
249349cc55cSDimitry Andric if (!NSec->GraphSection) {
2505ffd83dbSDimitry Andric LLVM_DEBUG({
251e8d8bef9SDimitry Andric dbgs() << " Skipping relocations for MachO section "
252349cc55cSDimitry Andric << NSec->SegName << "/" << NSec->SectName
2535ffd83dbSDimitry Andric << " which has no associated graph section\n";
2545ffd83dbSDimitry Andric });
2555ffd83dbSDimitry Andric continue;
2565ffd83dbSDimitry Andric }
2575ffd83dbSDimitry Andric }
2585ffd83dbSDimitry Andric
2595ffd83dbSDimitry Andric // Add relocations for section.
2600b57cec5SDimitry Andric for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
2610b57cec5SDimitry Andric RelItr != RelEnd; ++RelItr) {
2620b57cec5SDimitry Andric
2630b57cec5SDimitry Andric MachO::relocation_info RI = getRelocationInfo(RelItr);
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric // Find the address of the value to fix up.
26604eeddc0SDimitry Andric auto FixupAddress = SectionAddress + (uint32_t)RI.r_address;
2670b57cec5SDimitry Andric
2680b57cec5SDimitry Andric LLVM_DEBUG({
269349cc55cSDimitry Andric dbgs() << " " << NSec->SectName << " + "
270e8d8bef9SDimitry Andric << formatv("{0:x8}", RI.r_address) << ":\n";
2710b57cec5SDimitry Andric });
2720b57cec5SDimitry Andric
2738bcb0991SDimitry Andric // Find the block that the fixup points to.
2748bcb0991SDimitry Andric Block *BlockToFix = nullptr;
2750b57cec5SDimitry Andric {
276349cc55cSDimitry Andric auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
2778bcb0991SDimitry Andric if (!SymbolToFixOrErr)
2788bcb0991SDimitry Andric return SymbolToFixOrErr.takeError();
2798bcb0991SDimitry Andric BlockToFix = &SymbolToFixOrErr->getBlock();
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric
28204eeddc0SDimitry Andric if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
2838bcb0991SDimitry Andric BlockToFix->getAddress() + BlockToFix->getContent().size())
2840b57cec5SDimitry Andric return make_error<JITLinkError>(
2858bcb0991SDimitry Andric "Relocation extends past end of fixup block");
2860b57cec5SDimitry Andric
2870b57cec5SDimitry Andric // Get a pointer to the fixup content.
2888bcb0991SDimitry Andric const char *FixupContent = BlockToFix->getContent().data() +
2898bcb0991SDimitry Andric (FixupAddress - BlockToFix->getAddress());
2900b57cec5SDimitry Andric
291fe6060f1SDimitry Andric size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
292fe6060f1SDimitry Andric
2938bcb0991SDimitry Andric // The target symbol and addend will be populated by the switch below.
2948bcb0991SDimitry Andric Symbol *TargetSymbol = nullptr;
2950b57cec5SDimitry Andric uint64_t Addend = 0;
2960b57cec5SDimitry Andric
297349cc55cSDimitry Andric // Validate the relocation kind.
298fe6060f1SDimitry Andric auto MachORelocKind = getRelocKind(RI);
299fe6060f1SDimitry Andric if (!MachORelocKind)
300fe6060f1SDimitry Andric return MachORelocKind.takeError();
301fe6060f1SDimitry Andric
302fe6060f1SDimitry Andric Edge::Kind Kind = Edge::Invalid;
303fe6060f1SDimitry Andric
304fe6060f1SDimitry Andric switch (*MachORelocKind) {
305fe6060f1SDimitry Andric case MachOBranch32:
3068bcb0991SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3078bcb0991SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3080b57cec5SDimitry Andric else
3098bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
310480093f4SDimitry Andric Addend = *(const little32_t *)FixupContent;
311fe6060f1SDimitry Andric Kind = x86_64::BranchPCRel32;
3128bcb0991SDimitry Andric break;
313fe6060f1SDimitry Andric case MachOPCRel32:
314fe6060f1SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
315fe6060f1SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
316fe6060f1SDimitry Andric else
317fe6060f1SDimitry Andric return TargetSymbolOrErr.takeError();
318fe6060f1SDimitry Andric Addend = *(const little32_t *)FixupContent - 4;
319fe6060f1SDimitry Andric Kind = x86_64::Delta32;
320fe6060f1SDimitry Andric break;
321fe6060f1SDimitry Andric case MachOPCRel32GOTLoad:
322fe6060f1SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
323fe6060f1SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
324fe6060f1SDimitry Andric else
325fe6060f1SDimitry Andric return TargetSymbolOrErr.takeError();
326fe6060f1SDimitry Andric Addend = *(const little32_t *)FixupContent;
327349cc55cSDimitry Andric Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
328fe6060f1SDimitry Andric if (FixupOffset < 3)
329fe6060f1SDimitry Andric return make_error<JITLinkError>("GOTLD at invalid offset " +
330fe6060f1SDimitry Andric formatv("{0}", FixupOffset));
331fe6060f1SDimitry Andric break;
332fe6060f1SDimitry Andric case MachOPCRel32GOT:
333fe6060f1SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
334fe6060f1SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
335fe6060f1SDimitry Andric else
336fe6060f1SDimitry Andric return TargetSymbolOrErr.takeError();
337fe6060f1SDimitry Andric Addend = *(const little32_t *)FixupContent - 4;
338fe6060f1SDimitry Andric Kind = x86_64::RequestGOTAndTransformToDelta32;
339fe6060f1SDimitry Andric break;
340fe6060f1SDimitry Andric case MachOPCRel32TLV:
341fe6060f1SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
342fe6060f1SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
343fe6060f1SDimitry Andric else
344fe6060f1SDimitry Andric return TargetSymbolOrErr.takeError();
345fe6060f1SDimitry Andric Addend = *(const little32_t *)FixupContent;
346349cc55cSDimitry Andric Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
347349cc55cSDimitry Andric if (FixupOffset < 3)
348349cc55cSDimitry Andric return make_error<JITLinkError>("TLV at invalid offset " +
349349cc55cSDimitry Andric formatv("{0}", FixupOffset));
350fe6060f1SDimitry Andric break;
351fe6060f1SDimitry Andric case MachOPointer32:
3528bcb0991SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3538bcb0991SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3548bcb0991SDimitry Andric else
3558bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
3560b57cec5SDimitry Andric Addend = *(const ulittle32_t *)FixupContent;
357fe6060f1SDimitry Andric Kind = x86_64::Pointer32;
3580b57cec5SDimitry Andric break;
359fe6060f1SDimitry Andric case MachOPointer64:
3608bcb0991SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3618bcb0991SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3620b57cec5SDimitry Andric else
3638bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
3640b57cec5SDimitry Andric Addend = *(const ulittle64_t *)FixupContent;
365fe6060f1SDimitry Andric Kind = x86_64::Pointer64;
3660b57cec5SDimitry Andric break;
367fe6060f1SDimitry Andric case MachOPointer64Anon: {
36804eeddc0SDimitry Andric orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
369349cc55cSDimitry Andric auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
370349cc55cSDimitry Andric if (!TargetNSec)
371349cc55cSDimitry Andric return TargetNSec.takeError();
372349cc55cSDimitry Andric if (auto TargetSymbolOrErr =
373349cc55cSDimitry Andric findSymbolByAddress(*TargetNSec, TargetAddress))
3748bcb0991SDimitry Andric TargetSymbol = &*TargetSymbolOrErr;
3750b57cec5SDimitry Andric else
3768bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
3778bcb0991SDimitry Andric Addend = TargetAddress - TargetSymbol->getAddress();
378fe6060f1SDimitry Andric Kind = x86_64::Pointer64;
3790b57cec5SDimitry Andric break;
3800b57cec5SDimitry Andric }
381fe6060f1SDimitry Andric case MachOPCRel32Minus1:
382fe6060f1SDimitry Andric case MachOPCRel32Minus2:
383fe6060f1SDimitry Andric case MachOPCRel32Minus4:
3848bcb0991SDimitry Andric if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
3858bcb0991SDimitry Andric TargetSymbol = TargetSymbolOrErr->GraphSymbol;
3860b57cec5SDimitry Andric else
3878bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
388fe6060f1SDimitry Andric Addend = *(const little32_t *)FixupContent - 4;
389fe6060f1SDimitry Andric Kind = x86_64::Delta32;
3900b57cec5SDimitry Andric break;
391fe6060f1SDimitry Andric case MachOPCRel32Anon: {
39204eeddc0SDimitry Andric orc::ExecutorAddr TargetAddress(FixupAddress + 4 +
39304eeddc0SDimitry Andric *(const little32_t *)FixupContent);
394349cc55cSDimitry Andric auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
395349cc55cSDimitry Andric if (!TargetNSec)
396349cc55cSDimitry Andric return TargetNSec.takeError();
397349cc55cSDimitry Andric if (auto TargetSymbolOrErr =
398349cc55cSDimitry Andric findSymbolByAddress(*TargetNSec, TargetAddress))
3998bcb0991SDimitry Andric TargetSymbol = &*TargetSymbolOrErr;
4000b57cec5SDimitry Andric else
4018bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
402fe6060f1SDimitry Andric Addend = TargetAddress - TargetSymbol->getAddress() - 4;
403fe6060f1SDimitry Andric Kind = x86_64::Delta32;
4040b57cec5SDimitry Andric break;
4050b57cec5SDimitry Andric }
406fe6060f1SDimitry Andric case MachOPCRel32Minus1Anon:
407fe6060f1SDimitry Andric case MachOPCRel32Minus2Anon:
408fe6060f1SDimitry Andric case MachOPCRel32Minus4Anon: {
40904eeddc0SDimitry Andric orc::ExecutorAddrDiff Delta =
41004eeddc0SDimitry Andric 4 + orc::ExecutorAddrDiff(
411fe6060f1SDimitry Andric 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
41204eeddc0SDimitry Andric orc::ExecutorAddr TargetAddress =
413fe6060f1SDimitry Andric FixupAddress + Delta + *(const little32_t *)FixupContent;
414349cc55cSDimitry Andric auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
415349cc55cSDimitry Andric if (!TargetNSec)
416349cc55cSDimitry Andric return TargetNSec.takeError();
417349cc55cSDimitry Andric if (auto TargetSymbolOrErr =
418349cc55cSDimitry Andric findSymbolByAddress(*TargetNSec, TargetAddress))
4198bcb0991SDimitry Andric TargetSymbol = &*TargetSymbolOrErr;
4200b57cec5SDimitry Andric else
4218bcb0991SDimitry Andric return TargetSymbolOrErr.takeError();
422fe6060f1SDimitry Andric Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
423fe6060f1SDimitry Andric Kind = x86_64::Delta32;
4240b57cec5SDimitry Andric break;
4250b57cec5SDimitry Andric }
426fe6060f1SDimitry Andric case MachOSubtractor32:
427fe6060f1SDimitry Andric case MachOSubtractor64: {
4280b57cec5SDimitry Andric // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
4290b57cec5SDimitry Andric // parsePairRelocation handles the paired reloc, and returns the
4300b57cec5SDimitry Andric // edge kind to be used (either Delta32/Delta64, or
4310b57cec5SDimitry Andric // NegDelta32/NegDelta64, depending on the direction of the
4320b57cec5SDimitry Andric // subtraction) along with the addend.
4330b57cec5SDimitry Andric auto PairInfo =
434fe6060f1SDimitry Andric parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
435fe6060f1SDimitry Andric FixupAddress, FixupContent, ++RelItr, RelEnd);
4360b57cec5SDimitry Andric if (!PairInfo)
4370b57cec5SDimitry Andric return PairInfo.takeError();
438fe6060f1SDimitry Andric std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
4398bcb0991SDimitry Andric assert(TargetSymbol && "No target symbol from parsePairRelocation?");
4400b57cec5SDimitry Andric break;
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric }
4430b57cec5SDimitry Andric
4440b57cec5SDimitry Andric LLVM_DEBUG({
445e8d8bef9SDimitry Andric dbgs() << " ";
446fe6060f1SDimitry Andric Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
4470b57cec5SDimitry Andric Addend);
448fe6060f1SDimitry Andric printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
4490b57cec5SDimitry Andric dbgs() << "\n";
4500b57cec5SDimitry Andric });
451fe6060f1SDimitry Andric BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
4528bcb0991SDimitry Andric *TargetSymbol, Addend);
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric return Error::success();
4560b57cec5SDimitry Andric }
4570b57cec5SDimitry Andric };
4580b57cec5SDimitry Andric
buildGOTAndStubs_MachO_x86_64(LinkGraph & G)459349cc55cSDimitry Andric Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
460349cc55cSDimitry Andric x86_64::GOTTableManager GOT;
461349cc55cSDimitry Andric x86_64::PLTTableManager PLT(GOT);
462349cc55cSDimitry Andric visitExistingEdges(G, GOT, PLT);
4635ffd83dbSDimitry Andric return Error::success();
4645ffd83dbSDimitry Andric }
4655ffd83dbSDimitry Andric
466349cc55cSDimitry Andric } // namespace
467349cc55cSDimitry Andric
4680b57cec5SDimitry Andric namespace llvm {
4690b57cec5SDimitry Andric namespace jitlink {
4700b57cec5SDimitry Andric
4710b57cec5SDimitry Andric class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
4720b57cec5SDimitry Andric friend class JITLinker<MachOJITLinker_x86_64>;
4730b57cec5SDimitry Andric
4740b57cec5SDimitry Andric public:
MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)4750b57cec5SDimitry Andric MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
476e8d8bef9SDimitry Andric std::unique_ptr<LinkGraph> G,
4770b57cec5SDimitry Andric PassConfiguration PassConfig)
478e8d8bef9SDimitry Andric : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
4790b57cec5SDimitry Andric
4800b57cec5SDimitry Andric private:
applyFixup(LinkGraph & G,Block & B,const Edge & E) const481fe6060f1SDimitry Andric Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
482349cc55cSDimitry Andric return x86_64::applyFixup(G, B, E, nullptr);
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric };
4850b57cec5SDimitry Andric
486e8d8bef9SDimitry Andric Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer)487e8d8bef9SDimitry Andric createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
488e8d8bef9SDimitry Andric auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
489e8d8bef9SDimitry Andric if (!MachOObj)
490e8d8bef9SDimitry Andric return MachOObj.takeError();
49106c3fb27SDimitry Andric
49206c3fb27SDimitry Andric auto Features = (*MachOObj)->getFeatures();
49306c3fb27SDimitry Andric if (!Features)
49406c3fb27SDimitry Andric return Features.takeError();
49506c3fb27SDimitry Andric
49606c3fb27SDimitry Andric return MachOLinkGraphBuilder_x86_64(**MachOObj, std::move(*Features))
49706c3fb27SDimitry Andric .buildGraph();
498e8d8bef9SDimitry Andric }
4990b57cec5SDimitry Andric
link_MachO_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)500e8d8bef9SDimitry Andric void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
501e8d8bef9SDimitry Andric std::unique_ptr<JITLinkContext> Ctx) {
502e8d8bef9SDimitry Andric
503e8d8bef9SDimitry Andric PassConfiguration Config;
504e8d8bef9SDimitry Andric
505e8d8bef9SDimitry Andric if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
5065f757f3fSDimitry Andric // Add eh-frame passes.
507fe6060f1SDimitry Andric Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
508fe6060f1SDimitry Andric Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
509480093f4SDimitry Andric
510349cc55cSDimitry Andric // Add compact unwind splitter pass.
511349cc55cSDimitry Andric Config.PrePrunePasses.push_back(
512349cc55cSDimitry Andric CompactUnwindSplitter("__LD,__compact_unwind"));
513349cc55cSDimitry Andric
5140b57cec5SDimitry Andric // Add a mark-live pass.
515e8d8bef9SDimitry Andric if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
5160b57cec5SDimitry Andric Config.PrePrunePasses.push_back(std::move(MarkLive));
5170b57cec5SDimitry Andric else
5188bcb0991SDimitry Andric Config.PrePrunePasses.push_back(markAllSymbolsLive);
5190b57cec5SDimitry Andric
520*0fca6ea1SDimitry Andric // Resolve any external section start / end symbols.
521*0fca6ea1SDimitry Andric Config.PostAllocationPasses.push_back(
522*0fca6ea1SDimitry Andric createDefineExternalSectionStartAndEndSymbolsPass(
523*0fca6ea1SDimitry Andric identifyMachOSectionStartAndEndSymbols));
524*0fca6ea1SDimitry Andric
5250b57cec5SDimitry Andric // Add an in-place GOT/Stubs pass.
526349cc55cSDimitry Andric Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
5275ffd83dbSDimitry Andric
5285ffd83dbSDimitry Andric // Add GOT/Stubs optimizer pass.
529349cc55cSDimitry Andric Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric
532fe6060f1SDimitry Andric if (auto Err = Ctx->modifyPassConfig(*G, Config))
5330b57cec5SDimitry Andric return Ctx->notifyFailed(std::move(Err));
5340b57cec5SDimitry Andric
5350b57cec5SDimitry Andric // Construct a JITLinker and run the link function.
536e8d8bef9SDimitry Andric MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric
createEHFrameSplitterPass_MachO_x86_64()539fe6060f1SDimitry Andric LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
54081ad6265SDimitry Andric return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
5410b57cec5SDimitry Andric }
542fe6060f1SDimitry Andric
createEHFrameEdgeFixerPass_MachO_x86_64()543fe6060f1SDimitry Andric LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
544fe6060f1SDimitry Andric return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
54581ad6265SDimitry Andric x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32,
54681ad6265SDimitry Andric x86_64::Delta64, x86_64::NegDelta32);
5470b57cec5SDimitry Andric }
5480b57cec5SDimitry Andric
5490b57cec5SDimitry Andric } // end namespace jitlink
5500b57cec5SDimitry Andric } // end namespace llvm
551