1 //===- ARM64Common.h --------------------------------------------*- C++ -*-===//
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 #ifndef LLD_MACHO_ARCH_ARM64COMMON_H
10 #define LLD_MACHO_ARCH_ARM64COMMON_H
12 #include "InputFiles.h"
14 #include "SyntheticSections.h"
17 #include "llvm/BinaryFormat/MachO.h"
19 namespace lld::macho
{
21 struct ARM64Common
: TargetInfo
{
22 template <class LP
> ARM64Common(LP lp
) : TargetInfo(lp
) {}
24 int64_t getEmbeddedAddend(MemoryBufferRef
, uint64_t offset
,
25 const llvm::MachO::relocation_info
) const override
;
26 void relocateOne(uint8_t *loc
, const Reloc
&, uint64_t va
,
27 uint64_t pc
) const override
;
29 void relaxGotLoad(uint8_t *loc
, uint8_t type
) const override
;
30 uint64_t getPageSize() const override
{ return 16 * 1024; }
32 void handleDtraceReloc(const Symbol
*sym
, const Reloc
&r
,
33 uint8_t *loc
) const override
;
36 inline uint64_t bitField(uint64_t value
, int right
, int width
, int left
) {
37 return ((value
>> right
) & ((1 << width
) - 1)) << left
;
41 // +-----------+---------------------------------------------------+
43 // +-----------+---------------------------------------------------+
45 inline void encodeBranch26(uint32_t *loc
, const Reloc
&r
, uint32_t base
,
47 checkInt(loc
, r
, va
, 28);
48 // Since branch destinations are 4-byte aligned, the 2 least-
49 // significant bits are 0. They are right shifted off the end.
50 llvm::support::endian::write32le(loc
, base
| bitField(va
, 2, 26, 0));
53 inline void encodeBranch26(uint32_t *loc
, SymbolDiagnostic d
, uint32_t base
,
55 checkInt(loc
, d
, va
, 28);
56 llvm::support::endian::write32le(loc
, base
| bitField(va
, 2, 26, 0));
60 // +-+---+---------+-------------------------------------+---------+
61 // | |ilo| | immhi | |
62 // +-+---+---------+-------------------------------------+---------+
64 inline void encodePage21(uint32_t *loc
, const Reloc
&r
, uint32_t base
,
66 checkInt(loc
, r
, va
, 35);
67 llvm::support::endian::write32le(loc
, base
| bitField(va
, 12, 2, 29) |
68 bitField(va
, 14, 19, 5));
71 inline void encodePage21(uint32_t *loc
, SymbolDiagnostic d
, uint32_t base
,
73 checkInt(loc
, d
, va
, 35);
74 llvm::support::endian::write32le(loc
, base
| bitField(va
, 12, 2, 29) |
75 bitField(va
, 14, 19, 5));
78 void reportUnalignedLdrStr(void *loc
, const Reloc
&, uint64_t va
, int align
);
79 void reportUnalignedLdrStr(void *loc
, SymbolDiagnostic
, uint64_t va
, int align
);
82 // +-------------------+-----------------------+-------------------+
84 // +-------------------+-----------------------+-------------------+
86 template <typename Target
>
87 inline void encodePageOff12(uint32_t *loc
, Target t
, uint32_t base
,
90 if ((base
& 0x3b00'0000) == 0x3900'0000) { // load/store
92 if (scale
== 0 && (base
& 0x0480'0000) == 0x0480'0000) // 128-bit variant
95 const int size
= 1 << scale
;
96 if ((va
& (size
- 1)) != 0)
97 reportUnalignedLdrStr(loc
, t
, va
, size
);
99 // TODO(gkm): extract embedded addend and warn if != 0
100 // uint64_t addend = ((base & 0x003FFC00) >> 10);
101 llvm::support::endian::write32le(loc
,
102 base
| bitField(va
, scale
, 12 - scale
, 10));
105 inline uint64_t pageBits(uint64_t address
) {
106 const uint64_t pageMask
= ~0xfffull
;
107 return address
& pageMask
;
110 inline void writeStub(uint8_t *buf8
, const uint32_t stubCode
[3],
111 const macho::Symbol
&sym
, uint64_t pointerVA
) {
112 auto *buf32
= reinterpret_cast<uint32_t *>(buf8
);
113 constexpr size_t stubCodeSize
= 3 * sizeof(uint32_t);
114 SymbolDiagnostic d
= {&sym
, "stub"};
115 uint64_t pcPageBits
=
116 pageBits(in
.stubs
->addr
+ sym
.stubsIndex
* stubCodeSize
);
117 encodePage21(&buf32
[0], d
, stubCode
[0], pageBits(pointerVA
) - pcPageBits
);
118 encodePageOff12(&buf32
[1], d
, stubCode
[1], pointerVA
);
119 buf32
[2] = stubCode
[2];
123 inline void writeStubHelperHeader(uint8_t *buf8
,
124 const uint32_t stubHelperHeaderCode
[6]) {
125 auto *buf32
= reinterpret_cast<uint32_t *>(buf8
);
126 auto pcPageBits
= [](int i
) {
127 return pageBits(in
.stubHelper
->addr
+ i
* sizeof(uint32_t));
129 uint64_t loaderVA
= in
.imageLoaderCache
->getVA();
130 SymbolDiagnostic d
= {nullptr, "stub header helper"};
131 encodePage21(&buf32
[0], d
, stubHelperHeaderCode
[0],
132 pageBits(loaderVA
) - pcPageBits(0));
133 encodePageOff12(&buf32
[1], d
, stubHelperHeaderCode
[1], loaderVA
);
134 buf32
[2] = stubHelperHeaderCode
[2];
136 in
.got
->addr
+ in
.stubHelper
->stubBinder
->gotIndex
* LP::wordSize
;
137 encodePage21(&buf32
[3], d
, stubHelperHeaderCode
[3],
138 pageBits(binderVA
) - pcPageBits(3));
139 encodePageOff12(&buf32
[4], d
, stubHelperHeaderCode
[4], binderVA
);
140 buf32
[5] = stubHelperHeaderCode
[5];
143 inline void writeStubHelperEntry(uint8_t *buf8
,
144 const uint32_t stubHelperEntryCode
[3],
145 const Symbol
&sym
, uint64_t entryVA
) {
146 auto *buf32
= reinterpret_cast<uint32_t *>(buf8
);
147 auto pcVA
= [entryVA
](int i
) { return entryVA
+ i
* sizeof(uint32_t); };
148 uint64_t stubHelperHeaderVA
= in
.stubHelper
->addr
;
149 buf32
[0] = stubHelperEntryCode
[0];
150 encodeBranch26(&buf32
[1], {&sym
, "stub helper"}, stubHelperEntryCode
[1],
151 stubHelperHeaderVA
- pcVA(1));
152 buf32
[2] = sym
.lazyBindOffset
;
157 writeObjCMsgSendStub(uint8_t *buf
, const uint32_t objcStubsFastCode
[8],
158 Symbol
*sym
, uint64_t stubsAddr
, uint64_t stubOffset
,
159 uint64_t selrefsVA
, uint64_t selectorIndex
,
160 uint64_t gotAddr
, uint64_t msgSendIndex
) {
161 SymbolDiagnostic d
= {sym
, sym
->getName()};
162 auto *buf32
= reinterpret_cast<uint32_t *>(buf
);
164 auto pcPageBits
= [stubsAddr
, stubOffset
](int i
) {
165 return pageBits(stubsAddr
+ stubOffset
+ i
* sizeof(uint32_t));
168 uint64_t selectorOffset
= selectorIndex
* LP::wordSize
;
169 encodePage21(&buf32
[0], d
, objcStubsFastCode
[0],
170 pageBits(selrefsVA
+ selectorOffset
) - pcPageBits(0));
171 encodePageOff12(&buf32
[1], d
, objcStubsFastCode
[1],
172 selrefsVA
+ selectorOffset
);
173 encodePage21(&buf32
[2], d
, objcStubsFastCode
[2],
174 pageBits(gotAddr
) - pcPageBits(2));
175 encodePage21(&buf32
[3], d
, objcStubsFastCode
[3], msgSendIndex
* LP::wordSize
);
176 buf32
[4] = objcStubsFastCode
[4];
177 buf32
[5] = objcStubsFastCode
[5];
178 buf32
[6] = objcStubsFastCode
[6];
179 buf32
[7] = objcStubsFastCode
[7];
182 } // namespace lld::macho