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
;
183 bool FixingFromSymbol
= true;
184 if (&BlockToFix
== &FromSymbol
->getAddressable()) {
185 if (LLVM_UNLIKELY(&BlockToFix
== &ToSymbol
->getAddressable())) {
186 // From and To are symbols in the same block. Decide direction by offset
188 if (ToSymbol
->getAddress() > FixupAddress
)
189 FixingFromSymbol
= true;
190 else if (FromSymbol
->getAddress() > FixupAddress
)
191 FixingFromSymbol
= false;
193 FixingFromSymbol
= FromSymbol
->getAddress() >= ToSymbol
->getAddress();
195 FixingFromSymbol
= true;
197 if (&BlockToFix
== &ToSymbol
->getAddressable())
198 FixingFromSymbol
= false;
200 // BlockToFix was neither FromSymbol nor ToSymbol.
201 return make_error
<JITLinkError
>("SUBTRACTOR relocation must fix up "
202 "either 'A' or 'B' (or a symbol in one "
203 "of their alt-entry groups)");
207 if (FixingFromSymbol
) {
208 TargetSymbol
= ToSymbol
;
209 DeltaKind
= (SubRI
.r_length
== 3) ? x86_64::Delta64
: x86_64::Delta32
;
210 Addend
= FixupValue
+ (FixupAddress
- FromSymbol
->getAddress());
211 // FIXME: handle extern 'from'.
213 TargetSymbol
= FromSymbol
;
215 (SubRI
.r_length
== 3) ? x86_64::NegDelta64
: x86_64::NegDelta32
;
216 Addend
= FixupValue
- (FixupAddress
- ToSymbol
->getAddress());
219 return PairRelocInfo(DeltaKind
, TargetSymbol
, Addend
);
222 Error
addRelocations() override
{
223 using namespace support
;
224 auto &Obj
= getObject();
226 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
228 for (const auto &S
: Obj
.sections()) {
230 orc::ExecutorAddr
SectionAddress(S
.getAddress());
232 // Skip relocations virtual sections.
234 if (S
.relocation_begin() != S
.relocation_end())
235 return make_error
<JITLinkError
>("Virtual section contains "
241 findSectionByIndex(Obj
.getSectionIndex(S
.getRawDataRefImpl()));
243 return NSec
.takeError();
245 // Skip relocations for MachO sections without corresponding graph
248 if (!NSec
->GraphSection
) {
250 dbgs() << " Skipping relocations for MachO section "
251 << NSec
->SegName
<< "/" << NSec
->SectName
252 << " which has no associated graph section\n";
258 // Add relocations for section.
259 for (auto RelItr
= S
.relocation_begin(), RelEnd
= S
.relocation_end();
260 RelItr
!= RelEnd
; ++RelItr
) {
262 MachO::relocation_info RI
= getRelocationInfo(RelItr
);
264 // Find the address of the value to fix up.
265 auto FixupAddress
= SectionAddress
+ (uint32_t)RI
.r_address
;
268 dbgs() << " " << NSec
->SectName
<< " + "
269 << formatv("{0:x8}", RI
.r_address
) << ":\n";
272 // Find the block that the fixup points to.
273 Block
*BlockToFix
= nullptr;
275 auto SymbolToFixOrErr
= findSymbolByAddress(*NSec
, FixupAddress
);
276 if (!SymbolToFixOrErr
)
277 return SymbolToFixOrErr
.takeError();
278 BlockToFix
= &SymbolToFixOrErr
->getBlock();
281 if (FixupAddress
+ orc::ExecutorAddrDiff(1ULL << RI
.r_length
) >
282 BlockToFix
->getAddress() + BlockToFix
->getContent().size())
283 return make_error
<JITLinkError
>(
284 "Relocation extends past end of fixup block");
286 // Get a pointer to the fixup content.
287 const char *FixupContent
= BlockToFix
->getContent().data() +
288 (FixupAddress
- BlockToFix
->getAddress());
290 size_t FixupOffset
= FixupAddress
- BlockToFix
->getAddress();
292 // The target symbol and addend will be populated by the switch below.
293 Symbol
*TargetSymbol
= nullptr;
296 // Validate the relocation kind.
297 auto MachORelocKind
= getRelocKind(RI
);
299 return MachORelocKind
.takeError();
301 Edge::Kind Kind
= Edge::Invalid
;
303 switch (*MachORelocKind
) {
305 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
306 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
308 return TargetSymbolOrErr
.takeError();
309 Addend
= *(const little32_t
*)FixupContent
;
310 Kind
= x86_64::BranchPCRel32
;
313 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
314 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
316 return TargetSymbolOrErr
.takeError();
317 Addend
= *(const little32_t
*)FixupContent
- 4;
318 Kind
= x86_64::Delta32
;
320 case MachOPCRel32GOTLoad
:
321 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
322 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
324 return TargetSymbolOrErr
.takeError();
325 Addend
= *(const little32_t
*)FixupContent
;
326 Kind
= x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable
;
328 return make_error
<JITLinkError
>("GOTLD at invalid offset " +
329 formatv("{0}", FixupOffset
));
331 case MachOPCRel32GOT
:
332 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
333 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
335 return TargetSymbolOrErr
.takeError();
336 Addend
= *(const little32_t
*)FixupContent
- 4;
337 Kind
= x86_64::RequestGOTAndTransformToDelta32
;
339 case MachOPCRel32TLV
:
340 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
341 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
343 return TargetSymbolOrErr
.takeError();
344 Addend
= *(const little32_t
*)FixupContent
;
345 Kind
= x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable
;
347 return make_error
<JITLinkError
>("TLV at invalid offset " +
348 formatv("{0}", FixupOffset
));
351 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
352 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
354 return TargetSymbolOrErr
.takeError();
355 Addend
= *(const ulittle32_t
*)FixupContent
;
356 Kind
= x86_64::Pointer32
;
359 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
360 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
362 return TargetSymbolOrErr
.takeError();
363 Addend
= *(const ulittle64_t
*)FixupContent
;
364 Kind
= x86_64::Pointer64
;
366 case MachOPointer64Anon
: {
367 orc::ExecutorAddr
TargetAddress(*(const ulittle64_t
*)FixupContent
);
368 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
370 return TargetNSec
.takeError();
371 if (auto TargetSymbolOrErr
=
372 findSymbolByAddress(*TargetNSec
, TargetAddress
))
373 TargetSymbol
= &*TargetSymbolOrErr
;
375 return TargetSymbolOrErr
.takeError();
376 Addend
= TargetAddress
- TargetSymbol
->getAddress();
377 Kind
= x86_64::Pointer64
;
380 case MachOPCRel32Minus1
:
381 case MachOPCRel32Minus2
:
382 case MachOPCRel32Minus4
:
383 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
384 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
386 return TargetSymbolOrErr
.takeError();
387 Addend
= *(const little32_t
*)FixupContent
- 4;
388 Kind
= x86_64::Delta32
;
390 case MachOPCRel32Anon
: {
391 orc::ExecutorAddr
TargetAddress(FixupAddress
+ 4 +
392 *(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() - 4;
402 Kind
= x86_64::Delta32
;
405 case MachOPCRel32Minus1Anon
:
406 case MachOPCRel32Minus2Anon
:
407 case MachOPCRel32Minus4Anon
: {
408 orc::ExecutorAddrDiff Delta
=
409 4 + orc::ExecutorAddrDiff(
410 1ULL << (*MachORelocKind
- MachOPCRel32Minus1Anon
));
411 orc::ExecutorAddr TargetAddress
=
412 FixupAddress
+ Delta
+ *(const little32_t
*)FixupContent
;
413 auto TargetNSec
= findSectionByIndex(RI
.r_symbolnum
- 1);
415 return TargetNSec
.takeError();
416 if (auto TargetSymbolOrErr
=
417 findSymbolByAddress(*TargetNSec
, TargetAddress
))
418 TargetSymbol
= &*TargetSymbolOrErr
;
420 return TargetSymbolOrErr
.takeError();
421 Addend
= TargetAddress
- TargetSymbol
->getAddress() - Delta
;
422 Kind
= x86_64::Delta32
;
425 case MachOSubtractor32
:
426 case MachOSubtractor64
: {
427 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
428 // parsePairRelocation handles the paired reloc, and returns the
429 // edge kind to be used (either Delta32/Delta64, or
430 // NegDelta32/NegDelta64, depending on the direction of the
431 // subtraction) along with the addend.
433 parsePairRelocation(*BlockToFix
, *MachORelocKind
, RI
,
434 FixupAddress
, FixupContent
, ++RelItr
, RelEnd
);
436 return PairInfo
.takeError();
437 std::tie(Kind
, TargetSymbol
, Addend
) = *PairInfo
;
438 assert(TargetSymbol
&& "No target symbol from parsePairRelocation?");
445 Edge
GE(Kind
, FixupAddress
- BlockToFix
->getAddress(), *TargetSymbol
,
447 printEdge(dbgs(), *BlockToFix
, GE
, x86_64::getEdgeKindName(Kind
));
450 BlockToFix
->addEdge(Kind
, FixupAddress
- BlockToFix
->getAddress(),
451 *TargetSymbol
, Addend
);
454 return Error::success();
458 Error
buildGOTAndStubs_MachO_x86_64(LinkGraph
&G
) {
459 x86_64::GOTTableManager GOT
;
460 x86_64::PLTTableManager
PLT(GOT
);
461 visitExistingEdges(G
, GOT
, PLT
);
462 return Error::success();
470 class MachOJITLinker_x86_64
: public JITLinker
<MachOJITLinker_x86_64
> {
471 friend class JITLinker
<MachOJITLinker_x86_64
>;
474 MachOJITLinker_x86_64(std::unique_ptr
<JITLinkContext
> Ctx
,
475 std::unique_ptr
<LinkGraph
> G
,
476 PassConfiguration PassConfig
)
477 : JITLinker(std::move(Ctx
), std::move(G
), std::move(PassConfig
)) {}
480 Error
applyFixup(LinkGraph
&G
, Block
&B
, const Edge
&E
) const {
481 return x86_64::applyFixup(G
, B
, E
, nullptr);
485 Expected
<std::unique_ptr
<LinkGraph
>>
486 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer
) {
487 auto MachOObj
= object::ObjectFile::createMachOObjectFile(ObjectBuffer
);
489 return MachOObj
.takeError();
491 auto Features
= (*MachOObj
)->getFeatures();
493 return Features
.takeError();
495 return MachOLinkGraphBuilder_x86_64(**MachOObj
, std::move(*Features
))
499 void link_MachO_x86_64(std::unique_ptr
<LinkGraph
> G
,
500 std::unique_ptr
<JITLinkContext
> Ctx
) {
502 PassConfiguration Config
;
504 if (Ctx
->shouldAddDefaultTargetPasses(G
->getTargetTriple())) {
505 // Add eh-frame passes.
506 Config
.PrePrunePasses
.push_back(createEHFrameSplitterPass_MachO_x86_64());
507 Config
.PrePrunePasses
.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
509 // Add compact unwind splitter pass.
510 Config
.PrePrunePasses
.push_back(
511 CompactUnwindSplitter("__LD,__compact_unwind"));
513 // Add a mark-live pass.
514 if (auto MarkLive
= Ctx
->getMarkLivePass(G
->getTargetTriple()))
515 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
517 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
519 // Add an in-place GOT/Stubs pass.
520 Config
.PostPrunePasses
.push_back(buildGOTAndStubs_MachO_x86_64
);
522 // Add GOT/Stubs optimizer pass.
523 Config
.PreFixupPasses
.push_back(x86_64::optimizeGOTAndStubAccesses
);
526 if (auto Err
= Ctx
->modifyPassConfig(*G
, Config
))
527 return Ctx
->notifyFailed(std::move(Err
));
529 // Construct a JITLinker and run the link function.
530 MachOJITLinker_x86_64::link(std::move(Ctx
), std::move(G
), std::move(Config
));
533 LinkGraphPassFunction
createEHFrameSplitterPass_MachO_x86_64() {
534 return DWARFRecordSectionSplitter("__TEXT,__eh_frame");
537 LinkGraphPassFunction
createEHFrameEdgeFixerPass_MachO_x86_64() {
538 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize
,
539 x86_64::Pointer32
, x86_64::Pointer64
, x86_64::Delta32
,
540 x86_64::Delta64
, x86_64::NegDelta32
);
543 } // end namespace jitlink
544 } // end namespace llvm