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 "DefineExternalSectionStartAndEndSymbols.h"
18 #include "MachOLinkGraphBuilder.h"
20 #define DEBUG_TYPE "jitlink"
23 using namespace llvm::jitlink
;
27 class MachOLinkGraphBuilder_x86_64
: public MachOLinkGraphBuilder
{
29 MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile
&Obj
,
30 SubtargetFeatures Features
)
31 : MachOLinkGraphBuilder(Obj
, Triple("x86_64-apple-darwin"),
32 std::move(Features
), x86_64::getEdgeKindName
) {}
35 enum MachONormalizedRelocationType
: unsigned {
45 MachOPCRel32Minus1Anon
,
46 MachOPCRel32Minus2Anon
,
47 MachOPCRel32Minus4Anon
,
55 static Expected
<MachONormalizedRelocationType
>
56 getRelocKind(const MachO::relocation_info
&RI
) {
58 case MachO::X86_64_RELOC_UNSIGNED
:
61 return RI
.r_extern
? MachOPointer64
: MachOPointer64Anon
;
62 else if (RI
.r_extern
&& RI
.r_length
== 2)
63 return MachOPointer32
;
66 case MachO::X86_64_RELOC_SIGNED
:
67 if (RI
.r_pcrel
&& RI
.r_length
== 2)
68 return RI
.r_extern
? MachOPCRel32
: MachOPCRel32Anon
;
70 case MachO::X86_64_RELOC_BRANCH
:
71 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
74 case MachO::X86_64_RELOC_GOT_LOAD
:
75 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
76 return MachOPCRel32GOTLoad
;
78 case MachO::X86_64_RELOC_GOT
:
79 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
80 return MachOPCRel32GOT
;
82 case MachO::X86_64_RELOC_SUBTRACTOR
:
83 if (!RI
.r_pcrel
&& RI
.r_extern
) {
85 return MachOSubtractor32
;
86 else if (RI
.r_length
== 3)
87 return MachOSubtractor64
;
90 case MachO::X86_64_RELOC_SIGNED_1
:
91 if (RI
.r_pcrel
&& RI
.r_length
== 2)
92 return RI
.r_extern
? MachOPCRel32Minus1
: MachOPCRel32Minus1Anon
;
94 case MachO::X86_64_RELOC_SIGNED_2
:
95 if (RI
.r_pcrel
&& RI
.r_length
== 2)
96 return RI
.r_extern
? MachOPCRel32Minus2
: MachOPCRel32Minus2Anon
;
98 case MachO::X86_64_RELOC_SIGNED_4
:
99 if (RI
.r_pcrel
&& RI
.r_length
== 2)
100 return RI
.r_extern
? MachOPCRel32Minus4
: MachOPCRel32Minus4Anon
;
102 case MachO::X86_64_RELOC_TLV
:
103 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
104 return MachOPCRel32TLV
;
108 return make_error
<JITLinkError
>(
109 "Unsupported x86-64 relocation: address=" +
110 formatv("{0:x8}", RI
.r_address
) +
111 ", symbolnum=" + formatv("{0:x6}", RI
.r_symbolnum
) +
112 ", kind=" + formatv("{0:x1}", RI
.r_type
) +
113 ", pc_rel=" + (RI
.r_pcrel
? "true" : "false") +
114 ", extern=" + (RI
.r_extern
? "true" : "false") +
115 ", length=" + formatv("{0:d}", RI
.r_length
));
118 using PairRelocInfo
= std::tuple
<Edge::Kind
, Symbol
*, uint64_t>;
120 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
121 // returns the edge kind and addend to be used.
122 Expected
<PairRelocInfo
> parsePairRelocation(
123 Block
&BlockToFix
, MachONormalizedRelocationType SubtractorKind
,
124 const MachO::relocation_info
&SubRI
, orc::ExecutorAddr FixupAddress
,
125 const char *FixupContent
, object::relocation_iterator
&UnsignedRelItr
,
126 object::relocation_iterator
&RelEnd
) {
127 using namespace support
;
129 assert(((SubtractorKind
== MachOSubtractor32
&& SubRI
.r_length
== 2) ||
130 (SubtractorKind
== MachOSubtractor64
&& SubRI
.r_length
== 3)) &&
131 "Subtractor kind should match length");
132 assert(SubRI
.r_extern
&& "SUBTRACTOR reloc symbol should be extern");
133 assert(!SubRI
.r_pcrel
&& "SUBTRACTOR reloc should not be PCRel");
135 if (UnsignedRelItr
== RelEnd
)
136 return make_error
<JITLinkError
>("x86_64 SUBTRACTOR without paired "
137 "UNSIGNED relocation");
139 auto UnsignedRI
= getRelocationInfo(UnsignedRelItr
);
141 if (SubRI
.r_address
!= UnsignedRI
.r_address
)
142 return make_error
<JITLinkError
>("x86_64 SUBTRACTOR and paired UNSIGNED "
143 "point to different addresses");
145 if (SubRI
.r_length
!= UnsignedRI
.r_length
)
146 return make_error
<JITLinkError
>("length of x86_64 SUBTRACTOR and paired "
147 "UNSIGNED reloc must match");
150 if (auto FromSymbolOrErr
= findSymbolByIndex(SubRI
.r_symbolnum
))
151 FromSymbol
= FromSymbolOrErr
->GraphSymbol
;
153 return FromSymbolOrErr
.takeError();
155 // Read the current fixup value.
156 uint64_t FixupValue
= 0;
157 if (SubRI
.r_length
== 3)
158 FixupValue
= *(const little64_t
*)FixupContent
;
160 FixupValue
= *(const little32_t
*)FixupContent
;
162 // Find 'ToSymbol' using symbol number or address, depending on whether the
163 // paired UNSIGNED relocation is extern.
164 Symbol
*ToSymbol
= nullptr;
165 if (UnsignedRI
.r_extern
) {
166 // Find target symbol by symbol index.
167 if (auto ToSymbolOrErr
= findSymbolByIndex(UnsignedRI
.r_symbolnum
))
168 ToSymbol
= ToSymbolOrErr
->GraphSymbol
;
170 return ToSymbolOrErr
.takeError();
172 auto ToSymbolSec
= findSectionByIndex(UnsignedRI
.r_symbolnum
- 1);
174 return ToSymbolSec
.takeError();
175 ToSymbol
= getSymbolByAddress(*ToSymbolSec
, ToSymbolSec
->Address
);
176 assert(ToSymbol
&& "No symbol for section");
177 FixupValue
-= ToSymbol
->getAddress().getValue();
180 Edge::Kind DeltaKind
;
181 Symbol
*TargetSymbol
;
184 bool FixingFromSymbol
= true;
185 if (&BlockToFix
== &FromSymbol
->getAddressable()) {
186 if (LLVM_UNLIKELY(&BlockToFix
== &ToSymbol
->getAddressable())) {
187 // From and To are symbols in the same block. Decide direction by offset
189 if (ToSymbol
->getAddress() > FixupAddress
)
190 FixingFromSymbol
= true;
191 else if (FromSymbol
->getAddress() > FixupAddress
)
192 FixingFromSymbol
= false;
194 FixingFromSymbol
= FromSymbol
->getAddress() >= ToSymbol
->getAddress();
196 FixingFromSymbol
= true;
198 if (&BlockToFix
== &ToSymbol
->getAddressable())
199 FixingFromSymbol
= false;
201 // BlockToFix was neither FromSymbol nor ToSymbol.
202 return make_error
<JITLinkError
>("SUBTRACTOR relocation must fix up "
203 "either 'A' or 'B' (or a symbol in one "
204 "of their alt-entry groups)");
208 if (FixingFromSymbol
) {
209 TargetSymbol
= ToSymbol
;
210 DeltaKind
= (SubRI
.r_length
== 3) ? x86_64::Delta64
: x86_64::Delta32
;
211 Addend
= FixupValue
+ (FixupAddress
- FromSymbol
->getAddress());
212 // FIXME: handle extern 'from'.
214 TargetSymbol
= FromSymbol
;
216 (SubRI
.r_length
== 3) ? x86_64::NegDelta64
: x86_64::NegDelta32
;
217 Addend
= FixupValue
- (FixupAddress
- ToSymbol
->getAddress());
220 return PairRelocInfo(DeltaKind
, TargetSymbol
, Addend
);
223 Error
addRelocations() override
{
224 using namespace support
;
225 auto &Obj
= getObject();
227 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
229 for (const auto &S
: Obj
.sections()) {
231 orc::ExecutorAddr
SectionAddress(S
.getAddress());
233 // Skip relocations virtual sections.
235 if (S
.relocation_begin() != S
.relocation_end())
236 return make_error
<JITLinkError
>("Virtual section contains "
242 findSectionByIndex(Obj
.getSectionIndex(S
.getRawDataRefImpl()));
244 return NSec
.takeError();
246 // Skip relocations for MachO sections without corresponding graph
249 if (!NSec
->GraphSection
) {
251 dbgs() << " Skipping relocations for MachO section "
252 << NSec
->SegName
<< "/" << NSec
->SectName
253 << " which has no associated graph section\n";
259 // Add relocations for section.
260 for (auto RelItr
= S
.relocation_begin(), RelEnd
= S
.relocation_end();
261 RelItr
!= RelEnd
; ++RelItr
) {
263 MachO::relocation_info RI
= getRelocationInfo(RelItr
);
265 // Find the address of the value to fix up.
266 auto FixupAddress
= SectionAddress
+ (uint32_t)RI
.r_address
;
269 dbgs() << " " << NSec
->SectName
<< " + "
270 << formatv("{0:x8}", RI
.r_address
) << ":\n";
273 // Find the block that the fixup points to.
274 Block
*BlockToFix
= nullptr;
276 auto SymbolToFixOrErr
= findSymbolByAddress(*NSec
, FixupAddress
);
277 if (!SymbolToFixOrErr
)
278 return SymbolToFixOrErr
.takeError();
279 BlockToFix
= &SymbolToFixOrErr
->getBlock();
282 if (FixupAddress
+ orc::ExecutorAddrDiff(1ULL << RI
.r_length
) >
283 BlockToFix
->getAddress() + BlockToFix
->getContent().size())
284 return make_error
<JITLinkError
>(
285 "Relocation extends past end of fixup block");
287 // Get a pointer to the fixup content.
288 const char *FixupContent
= BlockToFix
->getContent().data() +
289 (FixupAddress
- BlockToFix
->getAddress());
291 size_t FixupOffset
= FixupAddress
- BlockToFix
->getAddress();
293 // The target symbol and addend will be populated by the switch below.
294 Symbol
*TargetSymbol
= nullptr;
297 // Validate the relocation kind.
298 auto MachORelocKind
= getRelocKind(RI
);
300 return MachORelocKind
.takeError();
302 Edge::Kind Kind
= Edge::Invalid
;
304 switch (*MachORelocKind
) {
306 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
307 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
309 return TargetSymbolOrErr
.takeError();
310 Addend
= *(const little32_t
*)FixupContent
;
311 Kind
= x86_64::BranchPCRel32
;
314 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
315 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
317 return TargetSymbolOrErr
.takeError();
318 Addend
= *(const little32_t
*)FixupContent
- 4;
319 Kind
= x86_64::Delta32
;
321 case MachOPCRel32GOTLoad
:
322 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
323 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
325 return TargetSymbolOrErr
.takeError();
326 Addend
= *(const little32_t
*)FixupContent
;
327 Kind
= x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable
;
329 return make_error
<JITLinkError
>("GOTLD at invalid offset " +
330 formatv("{0}", FixupOffset
));
332 case MachOPCRel32GOT
:
333 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
334 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
336 return TargetSymbolOrErr
.takeError();
337 Addend
= *(const little32_t
*)FixupContent
- 4;
338 Kind
= x86_64::RequestGOTAndTransformToDelta32
;
340 case MachOPCRel32TLV
:
341 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
342 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
344 return TargetSymbolOrErr
.takeError();
345 Addend
= *(const little32_t
*)FixupContent
;
346 Kind
= x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
;
348 return make_error
<JITLinkError
>("TLV at invalid offset " +
349 formatv("{0}", FixupOffset
));
352 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
353 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
355 return TargetSymbolOrErr
.takeError();
356 Addend
= *(const ulittle32_t
*)FixupContent
;
357 Kind
= x86_64::Pointer32
;
360 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
361 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
363 return TargetSymbolOrErr
.takeError();
364 Addend
= *(const ulittle64_t
*)FixupContent
;
365 Kind
= x86_64::Pointer64
;
367 case MachOPointer64Anon
: {
368 orc::ExecutorAddr
TargetAddress(*(const ulittle64_t
*)FixupContent
);
369 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
371 return TargetNSec
.takeError();
372 if (auto TargetSymbolOrErr
=
373 findSymbolByAddress(*TargetNSec
, TargetAddress
))
374 TargetSymbol
= &*TargetSymbolOrErr
;
376 return TargetSymbolOrErr
.takeError();
377 Addend
= TargetAddress
- TargetSymbol
->getAddress();
378 Kind
= x86_64::Pointer64
;
381 case MachOPCRel32Minus1
:
382 case MachOPCRel32Minus2
:
383 case MachOPCRel32Minus4
:
384 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
385 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
387 return TargetSymbolOrErr
.takeError();
388 Addend
= *(const little32_t
*)FixupContent
- 4;
389 Kind
= x86_64::Delta32
;
391 case MachOPCRel32Anon
: {
392 orc::ExecutorAddr
TargetAddress(FixupAddress
+ 4 +
393 *(const little32_t
*)FixupContent
);
394 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
396 return TargetNSec
.takeError();
397 if (auto TargetSymbolOrErr
=
398 findSymbolByAddress(*TargetNSec
, TargetAddress
))
399 TargetSymbol
= &*TargetSymbolOrErr
;
401 return TargetSymbolOrErr
.takeError();
402 Addend
= TargetAddress
- TargetSymbol
->getAddress() - 4;
403 Kind
= x86_64::Delta32
;
406 case MachOPCRel32Minus1Anon
:
407 case MachOPCRel32Minus2Anon
:
408 case MachOPCRel32Minus4Anon
: {
409 orc::ExecutorAddrDiff Delta
=
410 4 + orc::ExecutorAddrDiff(
411 1ULL << (*MachORelocKind
- MachOPCRel32Minus1Anon
));
412 orc::ExecutorAddr TargetAddress
=
413 FixupAddress
+ Delta
+ *(const little32_t
*)FixupContent
;
414 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
416 return TargetNSec
.takeError();
417 if (auto TargetSymbolOrErr
=
418 findSymbolByAddress(*TargetNSec
, TargetAddress
))
419 TargetSymbol
= &*TargetSymbolOrErr
;
421 return TargetSymbolOrErr
.takeError();
422 Addend
= TargetAddress
- TargetSymbol
->getAddress() - Delta
;
423 Kind
= x86_64::Delta32
;
426 case MachOSubtractor32
:
427 case MachOSubtractor64
: {
428 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
429 // parsePairRelocation handles the paired reloc, and returns the
430 // edge kind to be used (either Delta32/Delta64, or
431 // NegDelta32/NegDelta64, depending on the direction of the
432 // subtraction) along with the addend.
434 parsePairRelocation(*BlockToFix
, *MachORelocKind
, RI
,
435 FixupAddress
, FixupContent
, ++RelItr
, RelEnd
);
437 return PairInfo
.takeError();
438 std::tie(Kind
, TargetSymbol
, Addend
) = *PairInfo
;
439 assert(TargetSymbol
&& "No target symbol from parsePairRelocation?");
446 Edge
GE(Kind
, FixupAddress
- BlockToFix
->getAddress(), *TargetSymbol
,
448 printEdge(dbgs(), *BlockToFix
, GE
, x86_64::getEdgeKindName(Kind
));
451 BlockToFix
->addEdge(Kind
, FixupAddress
- BlockToFix
->getAddress(),
452 *TargetSymbol
, Addend
);
455 return Error::success();
459 Error
buildGOTAndStubs_MachO_x86_64(LinkGraph
&G
) {
460 x86_64::GOTTableManager GOT
;
461 x86_64::PLTTableManager
PLT(GOT
);
462 visitExistingEdges(G
, GOT
, PLT
);
463 return Error::success();
471 class MachOJITLinker_x86_64
: public JITLinker
<MachOJITLinker_x86_64
> {
472 friend class JITLinker
<MachOJITLinker_x86_64
>;
475 MachOJITLinker_x86_64(std::unique_ptr
<JITLinkContext
> Ctx
,
476 std::unique_ptr
<LinkGraph
> G
,
477 PassConfiguration PassConfig
)
478 : JITLinker(std::move(Ctx
), std::move(G
), std::move(PassConfig
)) {}
481 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
482 return x86_64::applyFixup(G
, B
, E
, nullptr);
486 Expected
<std::unique_ptr
<LinkGraph
>>
487 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer
) {
488 auto MachOObj
= object::ObjectFile::createMachOObjectFile(ObjectBuffer
);
490 return MachOObj
.takeError();
492 auto Features
= (*MachOObj
)->getFeatures();
494 return Features
.takeError();
496 return MachOLinkGraphBuilder_x86_64(**MachOObj
, std::move(*Features
))
500 void link_MachO_x86_64(std::unique_ptr
<LinkGraph
> G
,
501 std::unique_ptr
<JITLinkContext
> Ctx
) {
503 PassConfiguration Config
;
505 if (Ctx
->shouldAddDefaultTargetPasses(G
->getTargetTriple())) {
506 // Add eh-frame passes.
507 Config
.PrePrunePasses
.push_back(createEHFrameSplitterPass_MachO_x86_64());
508 Config
.PrePrunePasses
.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
510 // Add compact unwind splitter pass.
511 Config
.PrePrunePasses
.push_back(
512 CompactUnwindSplitter("__LD,__compact_unwind"));
514 // Add a mark-live pass.
515 if (auto MarkLive
= Ctx
->getMarkLivePass(G
->getTargetTriple()))
516 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
518 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
520 // Resolve any external section start / end symbols.
521 Config
.PostAllocationPasses
.push_back(
522 createDefineExternalSectionStartAndEndSymbolsPass(
523 identifyMachOSectionStartAndEndSymbols
));
525 // Add an in-place GOT/Stubs pass.
526 Config
.PostPrunePasses
.push_back(buildGOTAndStubs_MachO_x86_64
);
528 // Add GOT/Stubs optimizer pass.
529 Config
.PreFixupPasses
.push_back(x86_64::optimizeGOTAndStubAccesses
);
532 if (auto Err
= Ctx
->modifyPassConfig(*G
, Config
))
533 return Ctx
->notifyFailed(std::move(Err
));
535 // Construct a JITLinker and run the link function.
536 MachOJITLinker_x86_64::link(std::move(Ctx
), std::move(G
), std::move(Config
));
539 LinkGraphPassFunction
createEHFrameSplitterPass_MachO_x86_64() {
540 return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
543 LinkGraphPassFunction
createEHFrameEdgeFixerPass_MachO_x86_64() {
544 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize
,
545 x86_64::Pointer32
, x86_64::Pointer64
, x86_64::Delta32
,
546 x86_64::Delta64
, x86_64::NegDelta32
);
549 } // end namespace jitlink
550 } // end namespace llvm