1 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
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
7 //===----------------------------------------------------------------------===//
9 // MachO/x86-64 jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
14 #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"
15 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
17 #include "MachOLinkGraphBuilder.h"
19 #define DEBUG_TYPE "jitlink"
22 using namespace llvm::jitlink
;
26 class MachOLinkGraphBuilder_x86_64
: public MachOLinkGraphBuilder
{
28 MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile
&Obj
,
29 SubtargetFeatures Features
)
30 : MachOLinkGraphBuilder(Obj
, Triple("x86_64-apple-darwin"),
31 std::move(Features
), x86_64::getEdgeKindName
) {}
34 enum MachONormalizedRelocationType
: unsigned {
44 MachOPCRel32Minus1Anon
,
45 MachOPCRel32Minus2Anon
,
46 MachOPCRel32Minus4Anon
,
54 static Expected
<MachONormalizedRelocationType
>
55 getRelocKind(const MachO::relocation_info
&RI
) {
57 case MachO::X86_64_RELOC_UNSIGNED
:
60 return RI
.r_extern
? MachOPointer64
: MachOPointer64Anon
;
61 else if (RI
.r_extern
&& RI
.r_length
== 2)
62 return MachOPointer32
;
65 case MachO::X86_64_RELOC_SIGNED
:
66 if (RI
.r_pcrel
&& RI
.r_length
== 2)
67 return RI
.r_extern
? MachOPCRel32
: MachOPCRel32Anon
;
69 case MachO::X86_64_RELOC_BRANCH
:
70 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
73 case MachO::X86_64_RELOC_GOT_LOAD
:
74 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
75 return MachOPCRel32GOTLoad
;
77 case MachO::X86_64_RELOC_GOT
:
78 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
79 return MachOPCRel32GOT
;
81 case MachO::X86_64_RELOC_SUBTRACTOR
:
82 if (!RI
.r_pcrel
&& RI
.r_extern
) {
84 return MachOSubtractor32
;
85 else if (RI
.r_length
== 3)
86 return MachOSubtractor64
;
89 case MachO::X86_64_RELOC_SIGNED_1
:
90 if (RI
.r_pcrel
&& RI
.r_length
== 2)
91 return RI
.r_extern
? MachOPCRel32Minus1
: MachOPCRel32Minus1Anon
;
93 case MachO::X86_64_RELOC_SIGNED_2
:
94 if (RI
.r_pcrel
&& RI
.r_length
== 2)
95 return RI
.r_extern
? MachOPCRel32Minus2
: MachOPCRel32Minus2Anon
;
97 case MachO::X86_64_RELOC_SIGNED_4
:
98 if (RI
.r_pcrel
&& RI
.r_length
== 2)
99 return RI
.r_extern
? MachOPCRel32Minus4
: MachOPCRel32Minus4Anon
;
101 case MachO::X86_64_RELOC_TLV
:
102 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
103 return MachOPCRel32TLV
;
107 return make_error
<JITLinkError
>(
108 "Unsupported x86-64 relocation: address=" +
109 formatv("{0:x8}", RI
.r_address
) +
110 ", symbolnum=" + formatv("{0:x6}", RI
.r_symbolnum
) +
111 ", kind=" + formatv("{0:x1}", RI
.r_type
) +
112 ", pc_rel=" + (RI
.r_pcrel
? "true" : "false") +
113 ", extern=" + (RI
.r_extern
? "true" : "false") +
114 ", length=" + formatv("{0:d}", RI
.r_length
));
117 using PairRelocInfo
= std::tuple
<Edge::Kind
, Symbol
*, uint64_t>;
119 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
120 // returns the edge kind and addend to be used.
121 Expected
<PairRelocInfo
> parsePairRelocation(
122 Block
&BlockToFix
, MachONormalizedRelocationType SubtractorKind
,
123 const MachO::relocation_info
&SubRI
, orc::ExecutorAddr FixupAddress
,
124 const char *FixupContent
, object::relocation_iterator
&UnsignedRelItr
,
125 object::relocation_iterator
&RelEnd
) {
126 using namespace support
;
128 assert(((SubtractorKind
== MachOSubtractor32
&& SubRI
.r_length
== 2) ||
129 (SubtractorKind
== MachOSubtractor64
&& SubRI
.r_length
== 3)) &&
130 "Subtractor kind should match length");
131 assert(SubRI
.r_extern
&& "SUBTRACTOR reloc symbol should be extern");
132 assert(!SubRI
.r_pcrel
&& "SUBTRACTOR reloc should not be PCRel");
134 if (UnsignedRelItr
== RelEnd
)
135 return make_error
<JITLinkError
>("x86_64 SUBTRACTOR without paired "
136 "UNSIGNED relocation");
138 auto UnsignedRI
= getRelocationInfo(UnsignedRelItr
);
140 if (SubRI
.r_address
!= UnsignedRI
.r_address
)
141 return make_error
<JITLinkError
>("x86_64 SUBTRACTOR and paired UNSIGNED "
142 "point to different addresses");
144 if (SubRI
.r_length
!= UnsignedRI
.r_length
)
145 return make_error
<JITLinkError
>("length of x86_64 SUBTRACTOR and paired "
146 "UNSIGNED reloc must match");
149 if (auto FromSymbolOrErr
= findSymbolByIndex(SubRI
.r_symbolnum
))
150 FromSymbol
= FromSymbolOrErr
->GraphSymbol
;
152 return FromSymbolOrErr
.takeError();
154 // Read the current fixup value.
155 uint64_t FixupValue
= 0;
156 if (SubRI
.r_length
== 3)
157 FixupValue
= *(const little64_t
*)FixupContent
;
159 FixupValue
= *(const little32_t
*)FixupContent
;
161 // Find 'ToSymbol' using symbol number or address, depending on whether the
162 // paired UNSIGNED relocation is extern.
163 Symbol
*ToSymbol
= nullptr;
164 if (UnsignedRI
.r_extern
) {
165 // Find target symbol by symbol index.
166 if (auto ToSymbolOrErr
= findSymbolByIndex(UnsignedRI
.r_symbolnum
))
167 ToSymbol
= ToSymbolOrErr
->GraphSymbol
;
169 return ToSymbolOrErr
.takeError();
171 auto ToSymbolSec
= findSectionByIndex(UnsignedRI
.r_symbolnum
- 1);
173 return ToSymbolSec
.takeError();
174 ToSymbol
= getSymbolByAddress(*ToSymbolSec
, ToSymbolSec
->Address
);
175 assert(ToSymbol
&& "No symbol for section");
176 FixupValue
-= ToSymbol
->getAddress().getValue();
179 Edge::Kind DeltaKind
;
180 Symbol
*TargetSymbol
;
182 if (&BlockToFix
== &FromSymbol
->getAddressable()) {
183 TargetSymbol
= ToSymbol
;
184 DeltaKind
= (SubRI
.r_length
== 3) ? x86_64::Delta64
: x86_64::Delta32
;
185 Addend
= FixupValue
+ (FixupAddress
- FromSymbol
->getAddress());
186 // FIXME: handle extern 'from'.
187 } else if (&BlockToFix
== &ToSymbol
->getAddressable()) {
188 TargetSymbol
= FromSymbol
;
190 (SubRI
.r_length
== 3) ? x86_64::NegDelta64
: x86_64::NegDelta32
;
191 Addend
= FixupValue
- (FixupAddress
- ToSymbol
->getAddress());
193 // BlockToFix was neither FromSymbol nor ToSymbol.
194 return make_error
<JITLinkError
>("SUBTRACTOR relocation must fix up "
195 "either 'A' or 'B' (or a symbol in one "
196 "of their alt-entry chains)");
199 return PairRelocInfo(DeltaKind
, TargetSymbol
, Addend
);
202 Error
addRelocations() override
{
203 using namespace support
;
204 auto &Obj
= getObject();
206 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
208 for (const auto &S
: Obj
.sections()) {
210 orc::ExecutorAddr
SectionAddress(S
.getAddress());
212 // Skip relocations virtual sections.
214 if (S
.relocation_begin() != S
.relocation_end())
215 return make_error
<JITLinkError
>("Virtual section contains "
221 findSectionByIndex(Obj
.getSectionIndex(S
.getRawDataRefImpl()));
223 return NSec
.takeError();
225 // Skip relocations for MachO sections without corresponding graph
228 if (!NSec
->GraphSection
) {
230 dbgs() << " Skipping relocations for MachO section "
231 << NSec
->SegName
<< "/" << NSec
->SectName
232 << " which has no associated graph section\n";
238 // Add relocations for section.
239 for (auto RelItr
= S
.relocation_begin(), RelEnd
= S
.relocation_end();
240 RelItr
!= RelEnd
; ++RelItr
) {
242 MachO::relocation_info RI
= getRelocationInfo(RelItr
);
244 // Find the address of the value to fix up.
245 auto FixupAddress
= SectionAddress
+ (uint32_t)RI
.r_address
;
248 dbgs() << " " << NSec
->SectName
<< " + "
249 << formatv("{0:x8}", RI
.r_address
) << ":\n";
252 // Find the block that the fixup points to.
253 Block
*BlockToFix
= nullptr;
255 auto SymbolToFixOrErr
= findSymbolByAddress(*NSec
, FixupAddress
);
256 if (!SymbolToFixOrErr
)
257 return SymbolToFixOrErr
.takeError();
258 BlockToFix
= &SymbolToFixOrErr
->getBlock();
261 if (FixupAddress
+ orc::ExecutorAddrDiff(1ULL << RI
.r_length
) >
262 BlockToFix
->getAddress() + BlockToFix
->getContent().size())
263 return make_error
<JITLinkError
>(
264 "Relocation extends past end of fixup block");
266 // Get a pointer to the fixup content.
267 const char *FixupContent
= BlockToFix
->getContent().data() +
268 (FixupAddress
- BlockToFix
->getAddress());
270 size_t FixupOffset
= FixupAddress
- BlockToFix
->getAddress();
272 // The target symbol and addend will be populated by the switch below.
273 Symbol
*TargetSymbol
= nullptr;
276 // Validate the relocation kind.
277 auto MachORelocKind
= getRelocKind(RI
);
279 return MachORelocKind
.takeError();
281 Edge::Kind Kind
= Edge::Invalid
;
283 switch (*MachORelocKind
) {
285 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
286 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
288 return TargetSymbolOrErr
.takeError();
289 Addend
= *(const little32_t
*)FixupContent
;
290 Kind
= x86_64::BranchPCRel32
;
293 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
294 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
296 return TargetSymbolOrErr
.takeError();
297 Addend
= *(const little32_t
*)FixupContent
- 4;
298 Kind
= x86_64::Delta32
;
300 case MachOPCRel32GOTLoad
:
301 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
302 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
304 return TargetSymbolOrErr
.takeError();
305 Addend
= *(const little32_t
*)FixupContent
;
306 Kind
= x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable
;
308 return make_error
<JITLinkError
>("GOTLD at invalid offset " +
309 formatv("{0}", FixupOffset
));
311 case MachOPCRel32GOT
:
312 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
313 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
315 return TargetSymbolOrErr
.takeError();
316 Addend
= *(const little32_t
*)FixupContent
- 4;
317 Kind
= x86_64::RequestGOTAndTransformToDelta32
;
319 case MachOPCRel32TLV
:
320 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
321 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
323 return TargetSymbolOrErr
.takeError();
324 Addend
= *(const little32_t
*)FixupContent
;
325 Kind
= x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
;
327 return make_error
<JITLinkError
>("TLV at invalid offset " +
328 formatv("{0}", FixupOffset
));
331 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
332 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
334 return TargetSymbolOrErr
.takeError();
335 Addend
= *(const ulittle32_t
*)FixupContent
;
336 Kind
= x86_64::Pointer32
;
339 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
340 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
342 return TargetSymbolOrErr
.takeError();
343 Addend
= *(const ulittle64_t
*)FixupContent
;
344 Kind
= x86_64::Pointer64
;
346 case MachOPointer64Anon
: {
347 orc::ExecutorAddr
TargetAddress(*(const ulittle64_t
*)FixupContent
);
348 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
350 return TargetNSec
.takeError();
351 if (auto TargetSymbolOrErr
=
352 findSymbolByAddress(*TargetNSec
, TargetAddress
))
353 TargetSymbol
= &*TargetSymbolOrErr
;
355 return TargetSymbolOrErr
.takeError();
356 Addend
= TargetAddress
- TargetSymbol
->getAddress();
357 Kind
= x86_64::Pointer64
;
360 case MachOPCRel32Minus1
:
361 case MachOPCRel32Minus2
:
362 case MachOPCRel32Minus4
:
363 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
364 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
366 return TargetSymbolOrErr
.takeError();
367 Addend
= *(const little32_t
*)FixupContent
- 4;
368 Kind
= x86_64::Delta32
;
370 case MachOPCRel32Anon
: {
371 orc::ExecutorAddr
TargetAddress(FixupAddress
+ 4 +
372 *(const little32_t
*)FixupContent
);
373 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
375 return TargetNSec
.takeError();
376 if (auto TargetSymbolOrErr
=
377 findSymbolByAddress(*TargetNSec
, TargetAddress
))
378 TargetSymbol
= &*TargetSymbolOrErr
;
380 return TargetSymbolOrErr
.takeError();
381 Addend
= TargetAddress
- TargetSymbol
->getAddress() - 4;
382 Kind
= x86_64::Delta32
;
385 case MachOPCRel32Minus1Anon
:
386 case MachOPCRel32Minus2Anon
:
387 case MachOPCRel32Minus4Anon
: {
388 orc::ExecutorAddrDiff Delta
=
389 4 + orc::ExecutorAddrDiff(
390 1ULL << (*MachORelocKind
- MachOPCRel32Minus1Anon
));
391 orc::ExecutorAddr TargetAddress
=
392 FixupAddress
+ Delta
+ *(const little32_t
*)FixupContent
;
393 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
395 return TargetNSec
.takeError();
396 if (auto TargetSymbolOrErr
=
397 findSymbolByAddress(*TargetNSec
, TargetAddress
))
398 TargetSymbol
= &*TargetSymbolOrErr
;
400 return TargetSymbolOrErr
.takeError();
401 Addend
= TargetAddress
- TargetSymbol
->getAddress() - Delta
;
402 Kind
= x86_64::Delta32
;
405 case MachOSubtractor32
:
406 case MachOSubtractor64
: {
407 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
408 // parsePairRelocation handles the paired reloc, and returns the
409 // edge kind to be used (either Delta32/Delta64, or
410 // NegDelta32/NegDelta64, depending on the direction of the
411 // subtraction) along with the addend.
413 parsePairRelocation(*BlockToFix
, *MachORelocKind
, RI
,
414 FixupAddress
, FixupContent
, ++RelItr
, RelEnd
);
416 return PairInfo
.takeError();
417 std::tie(Kind
, TargetSymbol
, Addend
) = *PairInfo
;
418 assert(TargetSymbol
&& "No target symbol from parsePairRelocation?");
425 Edge
GE(Kind
, FixupAddress
- BlockToFix
->getAddress(), *TargetSymbol
,
427 printEdge(dbgs(), *BlockToFix
, GE
, x86_64::getEdgeKindName(Kind
));
430 BlockToFix
->addEdge(Kind
, FixupAddress
- BlockToFix
->getAddress(),
431 *TargetSymbol
, Addend
);
434 return Error::success();
438 Error
buildGOTAndStubs_MachO_x86_64(LinkGraph
&G
) {
439 x86_64::GOTTableManager GOT
;
440 x86_64::PLTTableManager
PLT(GOT
);
441 visitExistingEdges(G
, GOT
, PLT
);
442 return Error::success();
450 class MachOJITLinker_x86_64
: public JITLinker
<MachOJITLinker_x86_64
> {
451 friend class JITLinker
<MachOJITLinker_x86_64
>;
454 MachOJITLinker_x86_64(std::unique_ptr
<JITLinkContext
> Ctx
,
455 std::unique_ptr
<LinkGraph
> G
,
456 PassConfiguration PassConfig
)
457 : JITLinker(std::move(Ctx
), std::move(G
), std::move(PassConfig
)) {}
460 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
461 return x86_64::applyFixup(G
, B
, E
, nullptr);
465 Expected
<std::unique_ptr
<LinkGraph
>>
466 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer
) {
467 auto MachOObj
= object::ObjectFile::createMachOObjectFile(ObjectBuffer
);
469 return MachOObj
.takeError();
471 auto Features
= (*MachOObj
)->getFeatures();
473 return Features
.takeError();
475 return MachOLinkGraphBuilder_x86_64(**MachOObj
, std::move(*Features
))
479 void link_MachO_x86_64(std::unique_ptr
<LinkGraph
> G
,
480 std::unique_ptr
<JITLinkContext
> Ctx
) {
482 PassConfiguration Config
;
484 if (Ctx
->shouldAddDefaultTargetPasses(G
->getTargetTriple())) {
485 // Add eh-frame passes.
486 Config
.PrePrunePasses
.push_back(createEHFrameSplitterPass_MachO_x86_64());
487 Config
.PrePrunePasses
.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
489 // Add compact unwind splitter pass.
490 Config
.PrePrunePasses
.push_back(
491 CompactUnwindSplitter("__LD,__compact_unwind"));
493 // Add a mark-live pass.
494 if (auto MarkLive
= Ctx
->getMarkLivePass(G
->getTargetTriple()))
495 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
497 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
499 // Add an in-place GOT/Stubs pass.
500 Config
.PostPrunePasses
.push_back(buildGOTAndStubs_MachO_x86_64
);
502 // Add GOT/Stubs optimizer pass.
503 Config
.PreFixupPasses
.push_back(x86_64::optimizeGOTAndStubAccesses
);
506 if (auto Err
= Ctx
->modifyPassConfig(*G
, Config
))
507 return Ctx
->notifyFailed(std::move(Err
));
509 // Construct a JITLinker and run the link function.
510 MachOJITLinker_x86_64::link(std::move(Ctx
), std::move(G
), std::move(Config
));
513 LinkGraphPassFunction
createEHFrameSplitterPass_MachO_x86_64() {
514 return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
517 LinkGraphPassFunction
createEHFrameEdgeFixerPass_MachO_x86_64() {
518 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize
,
519 x86_64::Pointer32
, x86_64::Pointer64
, x86_64::Delta32
,
520 x86_64::Delta64
, x86_64::NegDelta32
);
523 } // end namespace jitlink
524 } // end namespace llvm