2 //----------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #include "Arch/ARM64Common.h"
11 #include "InputFiles.h"
13 #include "SyntheticSections.h"
16 #include "lld/Common/ErrorHandler.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/BinaryFormat/MachO.h"
20 #include "llvm/Support/Endian.h"
21 #include "llvm/Support/MathExtras.h"
23 using namespace llvm::MachO
;
24 using namespace llvm::support::endian
;
26 using namespace lld::macho
;
30 struct ARM64_32
: ARM64Common
{
32 void writeStub(uint8_t *buf
, const Symbol
&) const override
;
33 void writeStubHelperHeader(uint8_t *buf
) const override
;
34 void writeStubHelperEntry(uint8_t *buf
, const Symbol
&,
35 uint64_t entryAddr
) const override
;
40 // These are very similar to ARM64's relocation attributes, except that we don't
41 // have the BYTE8 flag set.
42 static constexpr std::array
<RelocAttrs
, 11> relocAttrsArray
{{
43 #define B(x) RelocAttrBits::x
44 {"UNSIGNED", B(UNSIGNED
) | B(ABSOLUTE
) | B(EXTERN
) | B(LOCAL
) | B(BYTE4
)},
45 {"SUBTRACTOR", B(SUBTRAHEND
) | B(EXTERN
) | B(BYTE4
)},
46 {"BRANCH26", B(PCREL
) | B(EXTERN
) | B(BRANCH
) | B(BYTE4
)},
47 {"PAGE21", B(PCREL
) | B(EXTERN
) | B(BYTE4
)},
48 {"PAGEOFF12", B(ABSOLUTE
) | B(EXTERN
) | B(BYTE4
)},
49 {"GOT_LOAD_PAGE21", B(PCREL
) | B(EXTERN
) | B(GOT
) | B(BYTE4
)},
50 {"GOT_LOAD_PAGEOFF12",
51 B(ABSOLUTE
) | B(EXTERN
) | B(GOT
) | B(LOAD
) | B(BYTE4
)},
52 {"POINTER_TO_GOT", B(PCREL
) | B(EXTERN
) | B(GOT
) | B(POINTER
) | B(BYTE4
)},
53 {"TLVP_LOAD_PAGE21", B(PCREL
) | B(EXTERN
) | B(TLV
) | B(BYTE4
)},
54 {"TLVP_LOAD_PAGEOFF12",
55 B(ABSOLUTE
) | B(EXTERN
) | B(TLV
) | B(LOAD
) | B(BYTE4
)},
56 {"ADDEND", B(ADDEND
)},
60 // The stub code is fairly similar to ARM64's, except that we load pointers into
61 // 32-bit 'w' registers, instead of the 64-bit 'x' ones.
63 static constexpr uint32_t stubCode
[] = {
64 0x90000010, // 00: adrp x16, __la_symbol_ptr@page
65 0xb9400210, // 04: ldr w16, [x16, __la_symbol_ptr@pageoff]
66 0xd61f0200, // 08: br x16
69 void ARM64_32::writeStub(uint8_t *buf8
, const Symbol
&sym
) const {
70 ::writeStub
<ILP32
>(buf8
, stubCode
, sym
);
73 static constexpr uint32_t stubHelperHeaderCode
[] = {
74 0x90000011, // 00: adrp x17, _dyld_private@page
75 0x91000231, // 04: add x17, x17, _dyld_private@pageoff
76 0xa9bf47f0, // 08: stp x16/x17, [sp, #-16]!
77 0x90000010, // 0c: adrp x16, dyld_stub_binder@page
78 0xb9400210, // 10: ldr w16, [x16, dyld_stub_binder@pageoff]
79 0xd61f0200, // 14: br x16
82 void ARM64_32::writeStubHelperHeader(uint8_t *buf8
) const {
83 ::writeStubHelperHeader
<ILP32
>(buf8
, stubHelperHeaderCode
);
86 static constexpr uint32_t stubHelperEntryCode
[] = {
87 0x18000050, // 00: ldr w16, l0
88 0x14000000, // 04: b stubHelperHeader
89 0x00000000, // 08: l0: .long 0
92 void ARM64_32::writeStubHelperEntry(uint8_t *buf8
, const Symbol
&sym
,
93 uint64_t entryVA
) const {
94 ::writeStubHelperEntry(buf8
, stubHelperEntryCode
, sym
, entryVA
);
97 ARM64_32::ARM64_32() : ARM64Common(ILP32()) {
98 cpuType
= CPU_TYPE_ARM64_32
;
99 cpuSubtype
= CPU_SUBTYPE_ARM64_V8
;
101 modeDwarfEncoding
= 0x04000000; // UNWIND_ARM_MODE_DWARF
102 subtractorRelocType
= GENERIC_RELOC_INVALID
; // FIXME
103 unsignedRelocType
= GENERIC_RELOC_INVALID
; // FIXME
105 stubSize
= sizeof(stubCode
);
106 stubHelperHeaderSize
= sizeof(stubHelperHeaderCode
);
107 stubHelperEntrySize
= sizeof(stubHelperEntryCode
);
109 relocAttrs
= {relocAttrsArray
.data(), relocAttrsArray
.size()};
112 TargetInfo
*macho::createARM64_32TargetInfo() {