1 //===---- MachO_arm64.cpp - JIT linker implementation for MachO/arm64 -----===//
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/arm64 jit-link implementation.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
15 #include "BasicGOTAndStubsBuilder.h"
16 #include "MachOLinkGraphBuilder.h"
18 #define DEBUG_TYPE "jitlink"
21 using namespace llvm::jitlink
;
22 using namespace llvm::jitlink::MachO_arm64_Edges
;
26 class MachOLinkGraphBuilder_arm64
: public MachOLinkGraphBuilder
{
28 MachOLinkGraphBuilder_arm64(const object::MachOObjectFile
&Obj
)
29 : MachOLinkGraphBuilder(Obj
),
30 NumSymbols(Obj
.getSymtabLoadCommand().nsyms
) {
31 addCustomSectionParser(
32 "__eh_frame", [this](NormalizedSection
&EHFrameSection
) {
33 if (!EHFrameSection
.Data
)
34 return make_error
<JITLinkError
>(
35 "__eh_frame section is marked zero-fill");
36 return MachOEHFrameBinaryParser(
37 *this, EHFrameSection
.Address
,
38 StringRef(EHFrameSection
.Data
, EHFrameSection
.Size
),
39 *EHFrameSection
.GraphSection
, 8, 4, NegDelta32
, Delta64
)
45 static Expected
<MachOARM64RelocationKind
>
46 getRelocationKind(const MachO::relocation_info
&RI
) {
48 case MachO::ARM64_RELOC_UNSIGNED
:
51 return RI
.r_extern
? Pointer64
: Pointer64Anon
;
52 else if (RI
.r_length
== 2)
56 case MachO::ARM64_RELOC_SUBTRACTOR
:
57 // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
58 // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
59 // They may be turned into NegDelta<W> by parsePairRelocation.
60 if (!RI
.r_pcrel
&& RI
.r_extern
) {
63 else if (RI
.r_length
== 3)
67 case MachO::ARM64_RELOC_BRANCH26
:
68 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
71 case MachO::ARM64_RELOC_PAGE21
:
72 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
75 case MachO::ARM64_RELOC_PAGEOFF12
:
76 if (!RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
79 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21
:
80 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
83 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12
:
84 if (!RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
85 return GOTPageOffset12
;
87 case MachO::ARM64_RELOC_POINTER_TO_GOT
:
88 if (RI
.r_pcrel
&& RI
.r_extern
&& RI
.r_length
== 2)
91 case MachO::ARM64_RELOC_ADDEND
:
92 if (!RI
.r_pcrel
&& !RI
.r_extern
&& RI
.r_length
== 2)
97 return make_error
<JITLinkError
>(
98 "Unsupported arm64 relocation: address=" +
99 formatv("{0:x8}", RI
.r_address
) +
100 ", symbolnum=" + formatv("{0:x6}", RI
.r_symbolnum
) +
101 ", kind=" + formatv("{0:x1}", RI
.r_type
) +
102 ", pc_rel=" + (RI
.r_pcrel
? "true" : "false") +
103 ", extern=" + (RI
.r_extern
? "true" : "false") +
104 ", length=" + formatv("{0:d}", RI
.r_length
));
107 MachO::relocation_info
108 getRelocationInfo(const object::relocation_iterator RelItr
) {
109 MachO::any_relocation_info ARI
=
110 getObject().getRelocation(RelItr
->getRawDataRefImpl());
111 MachO::relocation_info RI
;
112 memcpy(&RI
, &ARI
, sizeof(MachO::relocation_info
));
116 using PairRelocInfo
=
117 std::tuple
<MachOARM64RelocationKind
, 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
>
122 parsePairRelocation(Block
&BlockToFix
, Edge::Kind SubtractorKind
,
123 const MachO::relocation_info
&SubRI
,
124 JITTargetAddress FixupAddress
, const char *FixupContent
,
125 object::relocation_iterator
&UnsignedRelItr
,
126 object::relocation_iterator
&RelEnd
) {
127 using namespace support
;
129 assert(((SubtractorKind
== Delta32
&& SubRI
.r_length
== 2) ||
130 (SubtractorKind
== Delta64
&& 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
>("arm64 SUBTRACTOR without paired "
137 "UNSIGNED relocation");
139 auto UnsignedRI
= getRelocationInfo(UnsignedRelItr
);
141 if (SubRI
.r_address
!= UnsignedRI
.r_address
)
142 return make_error
<JITLinkError
>("arm64 SUBTRACTOR and paired UNSIGNED "
143 "point to different addresses");
145 if (SubRI
.r_length
!= UnsignedRI
.r_length
)
146 return make_error
<JITLinkError
>("length of arm64 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 if (auto ToSymbolOrErr
= findSymbolByAddress(FixupValue
))
173 ToSymbol
= &*ToSymbolOrErr
;
175 return ToSymbolOrErr
.takeError();
176 FixupValue
-= ToSymbol
->getAddress();
179 MachOARM64RelocationKind DeltaKind
;
180 Symbol
*TargetSymbol
;
182 if (&BlockToFix
== &FromSymbol
->getAddressable()) {
183 TargetSymbol
= ToSymbol
;
184 DeltaKind
= (SubRI
.r_length
== 3) ? Delta64
: Delta32
;
185 Addend
= FixupValue
+ (FixupAddress
- FromSymbol
->getAddress());
186 // FIXME: handle extern 'from'.
187 } else if (&BlockToFix
== &ToSymbol
->getAddressable()) {
188 TargetSymbol
= &*FromSymbol
;
189 DeltaKind
= (SubRI
.r_length
== 3) ? NegDelta64
: NegDelta32
;
190 Addend
= FixupValue
- (FixupAddress
- ToSymbol
->getAddress());
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 groups)");
198 return PairRelocInfo(DeltaKind
, TargetSymbol
, Addend
);
201 Error
addRelocations() override
{
202 using namespace support
;
203 auto &Obj
= getObject();
205 for (auto &S
: Obj
.sections()) {
207 JITTargetAddress SectionAddress
= S
.getAddress();
209 for (auto RelItr
= S
.relocation_begin(), RelEnd
= S
.relocation_end();
210 RelItr
!= RelEnd
; ++RelItr
) {
212 MachO::relocation_info RI
= getRelocationInfo(RelItr
);
214 // Sanity check the relocation kind.
215 auto Kind
= getRelocationKind(RI
);
217 return Kind
.takeError();
219 // Find the address of the value to fix up.
220 JITTargetAddress FixupAddress
= SectionAddress
+ (uint32_t)RI
.r_address
;
223 dbgs() << "Processing " << getMachOARM64RelocationKindName(*Kind
)
224 << " relocation at " << format("0x%016" PRIx64
, FixupAddress
)
228 // Find the block that the fixup points to.
229 Block
*BlockToFix
= nullptr;
231 auto SymbolToFixOrErr
= findSymbolByAddress(FixupAddress
);
232 if (!SymbolToFixOrErr
)
233 return SymbolToFixOrErr
.takeError();
234 BlockToFix
= &SymbolToFixOrErr
->getBlock();
237 if (FixupAddress
+ static_cast<JITTargetAddress
>(1ULL << RI
.r_length
) >
238 BlockToFix
->getAddress() + BlockToFix
->getContent().size())
239 return make_error
<JITLinkError
>(
240 "Relocation content extends past end of fixup block");
242 // Get a pointer to the fixup content.
243 const char *FixupContent
= BlockToFix
->getContent().data() +
244 (FixupAddress
- BlockToFix
->getAddress());
246 // The target symbol and addend will be populated by the switch below.
247 Symbol
*TargetSymbol
= nullptr;
250 if (*Kind
== PairedAddend
) {
251 // If this is an Addend relocation then process it and move to the
254 Addend
= RI
.r_symbolnum
;
256 if (RelItr
== RelEnd
)
257 return make_error
<JITLinkError
>("Unpaired Addend reloc at " +
258 formatv("{0:x16}", FixupAddress
));
260 RI
= getRelocationInfo(RelItr
);
262 Kind
= getRelocationKind(RI
);
264 return Kind
.takeError();
266 if (*Kind
!= Branch26
&& *Kind
!= Page21
&& *Kind
!= PageOffset12
)
267 return make_error
<JITLinkError
>(
268 "Invalid relocation pair: Addend + " +
269 getMachOARM64RelocationKindName(*Kind
));
272 dbgs() << " pair is " << getMachOARM64RelocationKindName(*Kind
)
276 // Find the address of the value to fix up.
277 JITTargetAddress PairedFixupAddress
=
278 SectionAddress
+ (uint32_t)RI
.r_address
;
279 if (PairedFixupAddress
!= FixupAddress
)
280 return make_error
<JITLinkError
>("Paired relocation points at "
286 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
287 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
289 return TargetSymbolOrErr
.takeError();
290 uint32_t Instr
= *(const ulittle32_t
*)FixupContent
;
291 if ((Instr
& 0x7fffffff) != 0x14000000)
292 return make_error
<JITLinkError
>("BRANCH26 target is not a B or BL "
293 "instruction with a zero addend");
297 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
298 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
300 return TargetSymbolOrErr
.takeError();
301 Addend
= *(const ulittle32_t
*)FixupContent
;
304 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
305 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
307 return TargetSymbolOrErr
.takeError();
308 Addend
= *(const ulittle64_t
*)FixupContent
;
310 case Pointer64Anon
: {
311 JITTargetAddress TargetAddress
= *(const ulittle64_t
*)FixupContent
;
312 if (auto TargetSymbolOrErr
= findSymbolByAddress(TargetAddress
))
313 TargetSymbol
= &*TargetSymbolOrErr
;
315 return TargetSymbolOrErr
.takeError();
316 Addend
= TargetAddress
- TargetSymbol
->getAddress();
321 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
322 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
324 return TargetSymbolOrErr
.takeError();
325 uint32_t Instr
= *(const ulittle32_t
*)FixupContent
;
326 if ((Instr
& 0xffffffe0) != 0x90000000)
327 return make_error
<JITLinkError
>("PAGE21/GOTPAGE21 target is not an "
328 "ADRP instruction with a zero "
333 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
334 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
336 return TargetSymbolOrErr
.takeError();
339 case GOTPageOffset12
: {
340 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
341 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
343 return TargetSymbolOrErr
.takeError();
344 uint32_t Instr
= *(const ulittle32_t
*)FixupContent
;
345 if ((Instr
& 0xfffffc00) != 0xf9400000)
346 return make_error
<JITLinkError
>("GOTPAGEOFF12 target is not an LDR "
347 "immediate instruction with a zero "
352 if (auto TargetSymbolOrErr
= findSymbolByIndex(RI
.r_symbolnum
))
353 TargetSymbol
= TargetSymbolOrErr
->GraphSymbol
;
355 return TargetSymbolOrErr
.takeError();
359 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
360 // parsePairRelocation handles the paired reloc, and returns the
361 // edge kind to be used (either Delta32/Delta64, or
362 // NegDelta32/NegDelta64, depending on the direction of the
363 // subtraction) along with the addend.
365 parsePairRelocation(*BlockToFix
, *Kind
, RI
, FixupAddress
,
366 FixupContent
, ++RelItr
, RelEnd
);
368 return PairInfo
.takeError();
369 std::tie(*Kind
, TargetSymbol
, Addend
) = *PairInfo
;
370 assert(TargetSymbol
&& "No target symbol from parsePairRelocation?");
374 llvm_unreachable("Special relocation kind should not appear in "
379 Edge
GE(*Kind
, FixupAddress
- BlockToFix
->getAddress(), *TargetSymbol
,
381 printEdge(dbgs(), *BlockToFix
, GE
,
382 getMachOARM64RelocationKindName(*Kind
));
385 BlockToFix
->addEdge(*Kind
, FixupAddress
- BlockToFix
->getAddress(),
386 *TargetSymbol
, Addend
);
389 return Error::success();
392 unsigned NumSymbols
= 0;
395 class MachO_arm64_GOTAndStubsBuilder
396 : public BasicGOTAndStubsBuilder
<MachO_arm64_GOTAndStubsBuilder
> {
398 MachO_arm64_GOTAndStubsBuilder(LinkGraph
&G
)
399 : BasicGOTAndStubsBuilder
<MachO_arm64_GOTAndStubsBuilder
>(G
) {}
401 bool isGOTEdge(Edge
&E
) const {
402 return E
.getKind() == GOTPage21
|| E
.getKind() == GOTPageOffset12
||
403 E
.getKind() == PointerToGOT
;
406 Symbol
&createGOTEntry(Symbol
&Target
) {
407 auto &GOTEntryBlock
= G
.createContentBlock(
408 getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
409 GOTEntryBlock
.addEdge(Pointer64
, 0, Target
, 0);
410 return G
.addAnonymousSymbol(GOTEntryBlock
, 0, 8, false, false);
413 void fixGOTEdge(Edge
&E
, Symbol
&GOTEntry
) {
414 if (E
.getKind() == GOTPage21
|| E
.getKind() == GOTPageOffset12
) {
415 // Update the target, but leave the edge addend as-is.
416 E
.setTarget(GOTEntry
);
417 } else if (E
.getKind() == PointerToGOT
) {
418 E
.setTarget(GOTEntry
);
421 llvm_unreachable("Not a GOT edge?");
424 bool isExternalBranchEdge(Edge
&E
) {
425 return E
.getKind() == Branch26
&& !E
.getTarget().isDefined();
428 Symbol
&createStub(Symbol
&Target
) {
429 auto &StubContentBlock
=
430 G
.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
431 // Re-use GOT entries for stub targets.
432 auto &GOTEntrySymbol
= getGOTEntrySymbol(Target
);
433 StubContentBlock
.addEdge(LDRLiteral19
, 0, GOTEntrySymbol
, 0);
434 return G
.addAnonymousSymbol(StubContentBlock
, 0, 8, true, false);
437 void fixExternalBranchEdge(Edge
&E
, Symbol
&Stub
) {
438 assert(E
.getKind() == Branch26
&& "Not a Branch32 edge?");
439 assert(E
.getAddend() == 0 && "Branch32 edge has non-zero addend?");
444 Section
&getGOTSection() {
446 GOTSection
= &G
.createSection("$__GOT", sys::Memory::MF_READ
);
450 Section
&getStubsSection() {
452 auto StubsProt
= static_cast<sys::Memory::ProtectionFlags
>(
453 sys::Memory::MF_READ
| sys::Memory::MF_EXEC
);
454 StubsSection
= &G
.createSection("$__STUBS", StubsProt
);
456 return *StubsSection
;
459 StringRef
getGOTEntryBlockContent() {
460 return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent
),
461 sizeof(NullGOTEntryContent
));
464 StringRef
getStubBlockContent() {
465 return StringRef(reinterpret_cast<const char *>(StubContent
),
466 sizeof(StubContent
));
469 static const uint8_t NullGOTEntryContent
[8];
470 static const uint8_t StubContent
[8];
471 Section
*GOTSection
= nullptr;
472 Section
*StubsSection
= nullptr;
475 const uint8_t MachO_arm64_GOTAndStubsBuilder::NullGOTEntryContent
[8] = {
476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
477 const uint8_t MachO_arm64_GOTAndStubsBuilder::StubContent
[8] = {
478 0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
479 0x00, 0x02, 0x1f, 0xd6 // BR x16
487 class MachOJITLinker_arm64
: public JITLinker
<MachOJITLinker_arm64
> {
488 friend class JITLinker
<MachOJITLinker_arm64
>;
491 MachOJITLinker_arm64(std::unique_ptr
<JITLinkContext
> Ctx
,
492 PassConfiguration PassConfig
)
493 : JITLinker(std::move(Ctx
), std::move(PassConfig
)) {}
496 StringRef
getEdgeKindName(Edge::Kind R
) const override
{
497 return getMachOARM64RelocationKindName(R
);
500 Expected
<std::unique_ptr
<LinkGraph
>>
501 buildGraph(MemoryBufferRef ObjBuffer
) override
{
502 auto MachOObj
= object::ObjectFile::createMachOObjectFile(ObjBuffer
);
504 return MachOObj
.takeError();
505 return MachOLinkGraphBuilder_arm64(**MachOObj
).buildGraph();
508 static Error
targetOutOfRangeError(const Block
&B
, const Edge
&E
) {
511 raw_string_ostream
ErrStream(ErrMsg
);
512 ErrStream
<< "Relocation target out of range: ";
513 printEdge(ErrStream
, B
, E
, getMachOARM64RelocationKindName(E
.getKind()));
516 return make_error
<JITLinkError
>(std::move(ErrMsg
));
519 static unsigned getPageOffset12Shift(uint32_t Instr
) {
520 constexpr uint32_t LDRLiteralMask
= 0x3ffffc00;
522 // Check for a GPR LDR immediate with a zero embedded literal.
523 // If found, the top two bits contain the shift.
524 if ((Instr
& LDRLiteralMask
) == 0x39400000)
527 // Check for a Neon LDR immediate of size 64-bit or less with a zero
528 // embedded literal. If found, the top two bits contain the shift.
529 if ((Instr
& LDRLiteralMask
) == 0x3d400000)
532 // Check for a Neon LDR immediate of size 128-bit with a zero embedded
534 constexpr uint32_t SizeBitsMask
= 0xc0000000;
535 if ((Instr
& (LDRLiteralMask
| SizeBitsMask
)) == 0x3dc00000)
541 Error
applyFixup(Block
&B
, const Edge
&E
, char *BlockWorkingMem
) const {
542 using namespace support
;
544 char *FixupPtr
= BlockWorkingMem
+ E
.getOffset();
545 JITTargetAddress FixupAddress
= B
.getAddress() + E
.getOffset();
547 switch (E
.getKind()) {
549 assert((FixupAddress
& 0x3) == 0 && "Branch-inst is not 32-bit aligned");
551 int64_t Value
= E
.getTarget().getAddress() - FixupAddress
+ E
.getAddend();
553 if (static_cast<uint64_t>(Value
) & 0x3)
554 return make_error
<JITLinkError
>("Branch26 target is not 32-bit "
557 if (Value
< -(1 << 27) || Value
> ((1 << 27) - 1))
558 return targetOutOfRangeError(B
, E
);
560 uint32_t RawInstr
= *(little32_t
*)FixupPtr
;
561 assert((RawInstr
& 0x7fffffff) == 0x14000000 &&
562 "RawInstr isn't a B or BR immediate instruction");
563 uint32_t Imm
= (static_cast<uint32_t>(Value
) & ((1 << 28) - 1)) >> 2;
564 uint32_t FixedInstr
= RawInstr
| Imm
;
565 *(little32_t
*)FixupPtr
= FixedInstr
;
569 uint64_t Value
= E
.getTarget().getAddress() + E
.getAddend();
570 if (Value
> std::numeric_limits
<uint32_t>::max())
571 return targetOutOfRangeError(B
, E
);
572 *(ulittle32_t
*)FixupPtr
= Value
;
576 uint64_t Value
= E
.getTarget().getAddress() + E
.getAddend();
577 *(ulittle64_t
*)FixupPtr
= Value
;
582 assert(E
.getAddend() == 0 && "PAGE21/GOTPAGE21 with non-zero addend");
583 uint64_t TargetPage
=
584 E
.getTarget().getAddress() & ~static_cast<uint64_t>(4096 - 1);
585 uint64_t PCPage
= B
.getAddress() & ~static_cast<uint64_t>(4096 - 1);
587 int64_t PageDelta
= TargetPage
- PCPage
;
588 if (PageDelta
< -(1 << 30) || PageDelta
> ((1 << 30) - 1))
589 return targetOutOfRangeError(B
, E
);
591 uint32_t RawInstr
= *(ulittle32_t
*)FixupPtr
;
592 assert((RawInstr
& 0xffffffe0) == 0x90000000 &&
593 "RawInstr isn't an ADRP instruction");
594 uint32_t ImmLo
= (static_cast<uint64_t>(PageDelta
) >> 12) & 0x3;
595 uint32_t ImmHi
= (static_cast<uint64_t>(PageDelta
) >> 14) & 0x7ffff;
596 uint32_t FixedInstr
= RawInstr
| (ImmLo
<< 29) | (ImmHi
<< 5);
597 *(ulittle32_t
*)FixupPtr
= FixedInstr
;
601 assert(E
.getAddend() == 0 && "PAGEOFF12 with non-zero addend");
602 uint64_t TargetOffset
= E
.getTarget().getAddress() & 0xfff;
604 uint32_t RawInstr
= *(ulittle32_t
*)FixupPtr
;
605 unsigned ImmShift
= getPageOffset12Shift(RawInstr
);
607 if (TargetOffset
& ((1 << ImmShift
) - 1))
608 return make_error
<JITLinkError
>("PAGEOFF12 target is not aligned");
610 uint32_t EncodedImm
= (TargetOffset
>> ImmShift
) << 10;
611 uint32_t FixedInstr
= RawInstr
| EncodedImm
;
612 *(ulittle32_t
*)FixupPtr
= FixedInstr
;
615 case GOTPageOffset12
: {
616 assert(E
.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
618 uint32_t RawInstr
= *(ulittle32_t
*)FixupPtr
;
619 assert((RawInstr
& 0xfffffc00) == 0xf9400000 &&
620 "RawInstr isn't a 64-bit LDR immediate");
622 uint32_t TargetOffset
= E
.getTarget().getAddress() & 0xfff;
623 assert((TargetOffset
& 0x7) == 0 && "GOT entry is not 8-byte aligned");
624 uint32_t EncodedImm
= (TargetOffset
>> 3) << 10;
625 uint32_t FixedInstr
= RawInstr
| EncodedImm
;
626 *(ulittle32_t
*)FixupPtr
= FixedInstr
;
630 assert((FixupAddress
& 0x3) == 0 && "LDR is not 32-bit aligned");
631 assert(E
.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
632 uint32_t RawInstr
= *(ulittle32_t
*)FixupPtr
;
633 assert(RawInstr
== 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
634 int64_t Delta
= E
.getTarget().getAddress() - FixupAddress
;
636 return make_error
<JITLinkError
>("LDR literal target is not 32-bit "
638 if (Delta
< -(1 << 20) || Delta
> ((1 << 20) - 1))
639 return targetOutOfRangeError(B
, E
);
641 uint32_t EncodedImm
= (static_cast<uint32_t>(Delta
) >> 2) << 5;
642 uint32_t FixedInstr
= RawInstr
| EncodedImm
;
643 *(ulittle32_t
*)FixupPtr
= FixedInstr
;
651 if (E
.getKind() == Delta32
|| E
.getKind() == Delta64
)
652 Value
= E
.getTarget().getAddress() - FixupAddress
+ E
.getAddend();
654 Value
= FixupAddress
- E
.getTarget().getAddress() + E
.getAddend();
656 if (E
.getKind() == Delta32
|| E
.getKind() == NegDelta32
) {
657 if (Value
< std::numeric_limits
<int32_t>::min() ||
658 Value
> std::numeric_limits
<int32_t>::max())
659 return targetOutOfRangeError(B
, E
);
660 *(little32_t
*)FixupPtr
= Value
;
662 *(little64_t
*)FixupPtr
= Value
;
666 llvm_unreachable("Unrecognized edge kind");
669 return Error::success();
672 uint64_t NullValue
= 0;
675 void jitLink_MachO_arm64(std::unique_ptr
<JITLinkContext
> Ctx
) {
676 PassConfiguration Config
;
677 Triple
TT("arm64-apple-ios");
679 if (Ctx
->shouldAddDefaultTargetPasses(TT
)) {
680 // Add a mark-live pass.
681 if (auto MarkLive
= Ctx
->getMarkLivePass(TT
))
682 Config
.PrePrunePasses
.push_back(std::move(MarkLive
));
684 Config
.PrePrunePasses
.push_back(markAllSymbolsLive
);
686 // Add an in-place GOT/Stubs pass.
687 Config
.PostPrunePasses
.push_back([](LinkGraph
&G
) -> Error
{
688 MachO_arm64_GOTAndStubsBuilder(G
).run();
689 return Error::success();
693 if (auto Err
= Ctx
->modifyPassConfig(TT
, Config
))
694 return Ctx
->notifyFailed(std::move(Err
));
696 // Construct a JITLinker and run the link function.
697 MachOJITLinker_arm64::link(std::move(Ctx
), std::move(Config
));
700 StringRef
getMachOARM64RelocationKindName(Edge::Kind R
) {
707 return "Pointer64Anon";
711 return "PageOffset12";
714 case GOTPageOffset12
:
715 return "GOTPageOffset12";
717 return "PointerToGOT";
719 return "PairedAddend";
721 return "LDRLiteral19";
731 return getGenericEdgeKindName(static_cast<Edge::Kind
>(R
));
735 } // end namespace jitlink
736 } // end namespace llvm