[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / ExecutionEngine / JITLink / MachO_x86_64.cpp
blob5e3b1e7b234f058f9ad5f8be19deca6f214ac4be
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.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
14 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
16 #include "MachOLinkGraphBuilder.h"
17 #include "PerGraphGOTAndPLTStubsBuilder.h"
19 #define DEBUG_TYPE "jitlink"
21 using namespace llvm;
22 using namespace llvm::jitlink;
24 namespace {
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) {}
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,
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;
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;
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;
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));
116 using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
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, JITTargetAddress FixupAddress,
123 const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
124 object::relocation_iterator &RelEnd) {
125 using namespace support;
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");
133 if (UnsignedRelItr == RelEnd)
134 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
135 "UNSIGNED relocation");
137 auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
139 if (SubRI.r_address != UnsignedRI.r_address)
140 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
141 "point to different addresses");
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");
147 Symbol *FromSymbol;
148 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
149 FromSymbol = FromSymbolOrErr->GraphSymbol;
150 else
151 return FromSymbolOrErr.takeError();
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;
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->Address);
174 assert(ToSymbol && "No symbol for section");
175 FixupValue -= ToSymbol->getAddress();
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)");
198 return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
201 Error addRelocations() override {
202 using namespace support;
203 auto &Obj = getObject();
205 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
207 for (auto &S : Obj.sections()) {
209 JITTargetAddress SectionAddress = S.getAddress();
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;
219 // Skip relocations for debug symbols.
221 auto &NSec =
222 getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
223 if (!NSec.GraphSection) {
224 LLVM_DEBUG({
225 dbgs() << " Skipping relocations for MachO section "
226 << NSec.SegName << "/" << NSec.SectName
227 << " which has no associated graph section\n";
229 continue;
233 // Add relocations for section.
234 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
235 RelItr != RelEnd; ++RelItr) {
237 MachO::relocation_info RI = getRelocationInfo(RelItr);
239 // Find the address of the value to fix up.
240 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
242 LLVM_DEBUG({
243 auto &NSec =
244 getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
245 dbgs() << " " << NSec.SectName << " + "
246 << formatv("{0:x8}", RI.r_address) << ":\n";
249 // Find the block that the fixup points to.
250 Block *BlockToFix = nullptr;
252 auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
253 if (!SymbolToFixOrErr)
254 return SymbolToFixOrErr.takeError();
255 BlockToFix = &SymbolToFixOrErr->getBlock();
258 if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
259 BlockToFix->getAddress() + BlockToFix->getContent().size())
260 return make_error<JITLinkError>(
261 "Relocation extends past end of fixup block");
263 // Get a pointer to the fixup content.
264 const char *FixupContent = BlockToFix->getContent().data() +
265 (FixupAddress - BlockToFix->getAddress());
267 size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
269 // The target symbol and addend will be populated by the switch below.
270 Symbol *TargetSymbol = nullptr;
271 uint64_t Addend = 0;
273 // Sanity check the relocation kind.
274 auto MachORelocKind = getRelocKind(RI);
275 if (!MachORelocKind)
276 return MachORelocKind.takeError();
278 Edge::Kind Kind = Edge::Invalid;
280 switch (*MachORelocKind) {
281 case MachOBranch32:
282 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
283 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
284 else
285 return TargetSymbolOrErr.takeError();
286 Addend = *(const little32_t *)FixupContent;
287 Kind = x86_64::BranchPCRel32;
288 break;
289 case MachOPCRel32:
290 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
291 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
292 else
293 return TargetSymbolOrErr.takeError();
294 Addend = *(const little32_t *)FixupContent - 4;
295 Kind = x86_64::Delta32;
296 break;
297 case MachOPCRel32GOTLoad:
298 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
299 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
300 else
301 return TargetSymbolOrErr.takeError();
302 Addend = *(const little32_t *)FixupContent;
303 Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
304 if (FixupOffset < 3)
305 return make_error<JITLinkError>("GOTLD at invalid offset " +
306 formatv("{0}", FixupOffset));
307 break;
308 case MachOPCRel32GOT:
309 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
310 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
311 else
312 return TargetSymbolOrErr.takeError();
313 Addend = *(const little32_t *)FixupContent - 4;
314 Kind = x86_64::RequestGOTAndTransformToDelta32;
315 break;
316 case MachOPCRel32TLV:
317 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
318 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
319 else
320 return TargetSymbolOrErr.takeError();
321 Addend = *(const little32_t *)FixupContent;
322 Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
323 if (FixupOffset < 3)
324 return make_error<JITLinkError>("TLV at invalid offset " +
325 formatv("{0}", FixupOffset));
326 break;
327 case MachOPointer32:
328 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
329 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
330 else
331 return TargetSymbolOrErr.takeError();
332 Addend = *(const ulittle32_t *)FixupContent;
333 Kind = x86_64::Pointer32;
334 break;
335 case MachOPointer64:
336 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
337 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
338 else
339 return TargetSymbolOrErr.takeError();
340 Addend = *(const ulittle64_t *)FixupContent;
341 Kind = x86_64::Pointer64;
342 break;
343 case MachOPointer64Anon: {
344 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
345 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
346 TargetSymbol = &*TargetSymbolOrErr;
347 else
348 return TargetSymbolOrErr.takeError();
349 Addend = TargetAddress - TargetSymbol->getAddress();
350 Kind = x86_64::Pointer64;
351 break;
353 case MachOPCRel32Minus1:
354 case MachOPCRel32Minus2:
355 case MachOPCRel32Minus4:
356 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
357 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
358 else
359 return TargetSymbolOrErr.takeError();
360 Addend = *(const little32_t *)FixupContent - 4;
361 Kind = x86_64::Delta32;
362 break;
363 case MachOPCRel32Anon: {
364 JITTargetAddress TargetAddress =
365 FixupAddress + 4 + *(const little32_t *)FixupContent;
366 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
367 TargetSymbol = &*TargetSymbolOrErr;
368 else
369 return TargetSymbolOrErr.takeError();
370 Addend = TargetAddress - TargetSymbol->getAddress() - 4;
371 Kind = x86_64::Delta32;
372 break;
374 case MachOPCRel32Minus1Anon:
375 case MachOPCRel32Minus2Anon:
376 case MachOPCRel32Minus4Anon: {
377 JITTargetAddress Delta =
378 4 + static_cast<JITTargetAddress>(
379 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
380 JITTargetAddress TargetAddress =
381 FixupAddress + Delta + *(const little32_t *)FixupContent;
382 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
383 TargetSymbol = &*TargetSymbolOrErr;
384 else
385 return TargetSymbolOrErr.takeError();
386 Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
387 Kind = x86_64::Delta32;
388 break;
390 case MachOSubtractor32:
391 case MachOSubtractor64: {
392 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
393 // parsePairRelocation handles the paired reloc, and returns the
394 // edge kind to be used (either Delta32/Delta64, or
395 // NegDelta32/NegDelta64, depending on the direction of the
396 // subtraction) along with the addend.
397 auto PairInfo =
398 parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
399 FixupAddress, FixupContent, ++RelItr, RelEnd);
400 if (!PairInfo)
401 return PairInfo.takeError();
402 std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
403 assert(TargetSymbol && "No target symbol from parsePairRelocation?");
404 break;
408 LLVM_DEBUG({
409 dbgs() << " ";
410 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
411 Addend);
412 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
413 dbgs() << "\n";
415 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
416 *TargetSymbol, Addend);
419 return Error::success();
423 class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64
424 : public PerGraphGOTAndPLTStubsBuilder<
425 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> {
426 public:
428 using PerGraphGOTAndPLTStubsBuilder<
429 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>::
430 PerGraphGOTAndPLTStubsBuilder;
432 bool isGOTEdgeToFix(Edge &E) const {
433 return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 ||
434 E.getKind() ==
435 x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
438 Symbol &createGOTEntry(Symbol &Target) {
439 return x86_64::createAnonymousPointer(G, getGOTSection(), &Target);
442 void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
443 // Fix the edge kind.
444 switch (E.getKind()) {
445 case x86_64::RequestGOTAndTransformToDelta32:
446 E.setKind(x86_64::Delta32);
447 break;
448 case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
449 E.setKind(x86_64::PCRel32GOTLoadREXRelaxable);
450 break;
451 default:
452 llvm_unreachable("Not a GOT transform edge");
454 // Fix the target, leave the addend as-is.
455 E.setTarget(GOTEntry);
458 bool isExternalBranchEdge(Edge &E) {
459 return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal();
462 Symbol &createPLTStub(Symbol &Target) {
463 return x86_64::createAnonymousPointerJumpStub(G, getStubsSection(),
464 getGOTEntry(Target));
467 void fixPLTEdge(Edge &E, Symbol &Stub) {
468 assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?");
469 assert(E.getAddend() == 0 &&
470 "BranchPCRel32 edge has unexpected addend value");
472 // Set the edge kind to BranchPCRel32ToPtrJumpStubBypassable. We will use
473 // this to check for stub optimization opportunities in the
474 // optimizeMachO_x86_64_GOTAndStubs pass below.
475 E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
476 E.setTarget(Stub);
479 private:
480 Section &getGOTSection() {
481 if (!GOTSection)
482 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
483 return *GOTSection;
486 Section &getStubsSection() {
487 if (!StubsSection) {
488 auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
489 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
490 StubsSection = &G.createSection("$__STUBS", StubsProt);
492 return *StubsSection;
495 Section *GOTSection = nullptr;
496 Section *StubsSection = nullptr;
499 } // namespace
501 namespace llvm {
502 namespace jitlink {
504 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
505 friend class JITLinker<MachOJITLinker_x86_64>;
507 public:
508 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
509 std::unique_ptr<LinkGraph> G,
510 PassConfiguration PassConfig)
511 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
513 private:
514 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
515 return x86_64::applyFixup(G, B, E, nullptr);
519 Expected<std::unique_ptr<LinkGraph>>
520 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
521 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
522 if (!MachOObj)
523 return MachOObj.takeError();
524 return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
527 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
528 std::unique_ptr<JITLinkContext> Ctx) {
530 PassConfiguration Config;
532 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
533 // Add eh-frame passses.
534 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
535 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
537 // Add a mark-live pass.
538 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
539 Config.PrePrunePasses.push_back(std::move(MarkLive));
540 else
541 Config.PrePrunePasses.push_back(markAllSymbolsLive);
543 // Add an in-place GOT/Stubs pass.
544 Config.PostPrunePasses.push_back(
545 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass);
547 // Add GOT/Stubs optimizer pass.
548 Config.PreFixupPasses.push_back(x86_64::optimize_x86_64_GOTAndStubs);
551 if (auto Err = Ctx->modifyPassConfig(*G, Config))
552 return Ctx->notifyFailed(std::move(Err));
554 // Construct a JITLinker and run the link function.
555 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
558 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
559 return EHFrameSplitter("__TEXT,__eh_frame");
562 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
563 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
564 x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
567 } // end namespace jitlink
568 } // end namespace llvm