annotate llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children 0572611fdcc8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===---- MachO_arm64.cpp - JIT linker implementation for MachO/arm64 -----===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // MachO/arm64 jit-link implementation.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
12
anatofuz
parents:
diff changeset
13 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
anatofuz
parents:
diff changeset
14
anatofuz
parents:
diff changeset
15 #include "BasicGOTAndStubsBuilder.h"
anatofuz
parents:
diff changeset
16 #include "MachOLinkGraphBuilder.h"
anatofuz
parents:
diff changeset
17
anatofuz
parents:
diff changeset
18 #define DEBUG_TYPE "jitlink"
anatofuz
parents:
diff changeset
19
anatofuz
parents:
diff changeset
20 using namespace llvm;
anatofuz
parents:
diff changeset
21 using namespace llvm::jitlink;
anatofuz
parents:
diff changeset
22 using namespace llvm::jitlink::MachO_arm64_Edges;
anatofuz
parents:
diff changeset
23
anatofuz
parents:
diff changeset
24 namespace {
anatofuz
parents:
diff changeset
25
anatofuz
parents:
diff changeset
26 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
anatofuz
parents:
diff changeset
27 public:
anatofuz
parents:
diff changeset
28 MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj)
anatofuz
parents:
diff changeset
29 : MachOLinkGraphBuilder(Obj),
anatofuz
parents:
diff changeset
30 NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
anatofuz
parents:
diff changeset
31
anatofuz
parents:
diff changeset
32 private:
anatofuz
parents:
diff changeset
33 static Expected<MachOARM64RelocationKind>
anatofuz
parents:
diff changeset
34 getRelocationKind(const MachO::relocation_info &RI) {
anatofuz
parents:
diff changeset
35 switch (RI.r_type) {
anatofuz
parents:
diff changeset
36 case MachO::ARM64_RELOC_UNSIGNED:
anatofuz
parents:
diff changeset
37 if (!RI.r_pcrel) {
anatofuz
parents:
diff changeset
38 if (RI.r_length == 3)
anatofuz
parents:
diff changeset
39 return RI.r_extern ? Pointer64 : Pointer64Anon;
anatofuz
parents:
diff changeset
40 else if (RI.r_length == 2)
anatofuz
parents:
diff changeset
41 return Pointer32;
anatofuz
parents:
diff changeset
42 }
anatofuz
parents:
diff changeset
43 break;
anatofuz
parents:
diff changeset
44 case MachO::ARM64_RELOC_SUBTRACTOR:
anatofuz
parents:
diff changeset
45 // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
anatofuz
parents:
diff changeset
46 // Initially represent SUBTRACTOR relocations with 'Delta<W>'.
anatofuz
parents:
diff changeset
47 // They may be turned into NegDelta<W> by parsePairRelocation.
anatofuz
parents:
diff changeset
48 if (!RI.r_pcrel && RI.r_extern) {
anatofuz
parents:
diff changeset
49 if (RI.r_length == 2)
anatofuz
parents:
diff changeset
50 return Delta32;
anatofuz
parents:
diff changeset
51 else if (RI.r_length == 3)
anatofuz
parents:
diff changeset
52 return Delta64;
anatofuz
parents:
diff changeset
53 }
anatofuz
parents:
diff changeset
54 break;
anatofuz
parents:
diff changeset
55 case MachO::ARM64_RELOC_BRANCH26:
anatofuz
parents:
diff changeset
56 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
57 return Branch26;
anatofuz
parents:
diff changeset
58 break;
anatofuz
parents:
diff changeset
59 case MachO::ARM64_RELOC_PAGE21:
anatofuz
parents:
diff changeset
60 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
61 return Page21;
anatofuz
parents:
diff changeset
62 break;
anatofuz
parents:
diff changeset
63 case MachO::ARM64_RELOC_PAGEOFF12:
anatofuz
parents:
diff changeset
64 if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
65 return PageOffset12;
anatofuz
parents:
diff changeset
66 break;
anatofuz
parents:
diff changeset
67 case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
anatofuz
parents:
diff changeset
68 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
69 return GOTPage21;
anatofuz
parents:
diff changeset
70 break;
anatofuz
parents:
diff changeset
71 case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
anatofuz
parents:
diff changeset
72 if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
73 return GOTPageOffset12;
anatofuz
parents:
diff changeset
74 break;
anatofuz
parents:
diff changeset
75 case MachO::ARM64_RELOC_POINTER_TO_GOT:
anatofuz
parents:
diff changeset
76 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
77 return PointerToGOT;
anatofuz
parents:
diff changeset
78 break;
anatofuz
parents:
diff changeset
79 case MachO::ARM64_RELOC_ADDEND:
anatofuz
parents:
diff changeset
80 if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2)
anatofuz
parents:
diff changeset
81 return PairedAddend;
anatofuz
parents:
diff changeset
82 break;
anatofuz
parents:
diff changeset
83 }
anatofuz
parents:
diff changeset
84
anatofuz
parents:
diff changeset
85 return make_error<JITLinkError>(
anatofuz
parents:
diff changeset
86 "Unsupported arm64 relocation: address=" +
anatofuz
parents:
diff changeset
87 formatv("{0:x8}", RI.r_address) +
anatofuz
parents:
diff changeset
88 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
anatofuz
parents:
diff changeset
89 ", kind=" + formatv("{0:x1}", RI.r_type) +
anatofuz
parents:
diff changeset
90 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
anatofuz
parents:
diff changeset
91 ", extern=" + (RI.r_extern ? "true" : "false") +
anatofuz
parents:
diff changeset
92 ", length=" + formatv("{0:d}", RI.r_length));
anatofuz
parents:
diff changeset
93 }
anatofuz
parents:
diff changeset
94
anatofuz
parents:
diff changeset
95 MachO::relocation_info
anatofuz
parents:
diff changeset
96 getRelocationInfo(const object::relocation_iterator RelItr) {
anatofuz
parents:
diff changeset
97 MachO::any_relocation_info ARI =
anatofuz
parents:
diff changeset
98 getObject().getRelocation(RelItr->getRawDataRefImpl());
anatofuz
parents:
diff changeset
99 MachO::relocation_info RI;
anatofuz
parents:
diff changeset
100 memcpy(&RI, &ARI, sizeof(MachO::relocation_info));
anatofuz
parents:
diff changeset
101 return RI;
anatofuz
parents:
diff changeset
102 }
anatofuz
parents:
diff changeset
103
anatofuz
parents:
diff changeset
104 using PairRelocInfo =
anatofuz
parents:
diff changeset
105 std::tuple<MachOARM64RelocationKind, Symbol *, uint64_t>;
anatofuz
parents:
diff changeset
106
anatofuz
parents:
diff changeset
107 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
anatofuz
parents:
diff changeset
108 // returns the edge kind and addend to be used.
anatofuz
parents:
diff changeset
109 Expected<PairRelocInfo>
anatofuz
parents:
diff changeset
110 parsePairRelocation(Block &BlockToFix, Edge::Kind SubtractorKind,
anatofuz
parents:
diff changeset
111 const MachO::relocation_info &SubRI,
anatofuz
parents:
diff changeset
112 JITTargetAddress FixupAddress, const char *FixupContent,
anatofuz
parents:
diff changeset
113 object::relocation_iterator &UnsignedRelItr,
anatofuz
parents:
diff changeset
114 object::relocation_iterator &RelEnd) {
anatofuz
parents:
diff changeset
115 using namespace support;
anatofuz
parents:
diff changeset
116
anatofuz
parents:
diff changeset
117 assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
anatofuz
parents:
diff changeset
118 (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
anatofuz
parents:
diff changeset
119 "Subtractor kind should match length");
anatofuz
parents:
diff changeset
120 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
anatofuz
parents:
diff changeset
121 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 if (UnsignedRelItr == RelEnd)
anatofuz
parents:
diff changeset
124 return make_error<JITLinkError>("arm64 SUBTRACTOR without paired "
anatofuz
parents:
diff changeset
125 "UNSIGNED relocation");
anatofuz
parents:
diff changeset
126
anatofuz
parents:
diff changeset
127 auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
anatofuz
parents:
diff changeset
128
anatofuz
parents:
diff changeset
129 if (SubRI.r_address != UnsignedRI.r_address)
anatofuz
parents:
diff changeset
130 return make_error<JITLinkError>("arm64 SUBTRACTOR and paired UNSIGNED "
anatofuz
parents:
diff changeset
131 "point to different addresses");
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 if (SubRI.r_length != UnsignedRI.r_length)
anatofuz
parents:
diff changeset
134 return make_error<JITLinkError>("length of arm64 SUBTRACTOR and paired "
anatofuz
parents:
diff changeset
135 "UNSIGNED reloc must match");
anatofuz
parents:
diff changeset
136
anatofuz
parents:
diff changeset
137 Symbol *FromSymbol;
anatofuz
parents:
diff changeset
138 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
anatofuz
parents:
diff changeset
139 FromSymbol = FromSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
140 else
anatofuz
parents:
diff changeset
141 return FromSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
142
anatofuz
parents:
diff changeset
143 // Read the current fixup value.
anatofuz
parents:
diff changeset
144 uint64_t FixupValue = 0;
anatofuz
parents:
diff changeset
145 if (SubRI.r_length == 3)
anatofuz
parents:
diff changeset
146 FixupValue = *(const little64_t *)FixupContent;
anatofuz
parents:
diff changeset
147 else
anatofuz
parents:
diff changeset
148 FixupValue = *(const little32_t *)FixupContent;
anatofuz
parents:
diff changeset
149
anatofuz
parents:
diff changeset
150 // Find 'ToSymbol' using symbol number or address, depending on whether the
anatofuz
parents:
diff changeset
151 // paired UNSIGNED relocation is extern.
anatofuz
parents:
diff changeset
152 Symbol *ToSymbol = nullptr;
anatofuz
parents:
diff changeset
153 if (UnsignedRI.r_extern) {
anatofuz
parents:
diff changeset
154 // Find target symbol by symbol index.
anatofuz
parents:
diff changeset
155 if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum))
anatofuz
parents:
diff changeset
156 ToSymbol = ToSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
157 else
anatofuz
parents:
diff changeset
158 return ToSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
159 } else {
anatofuz
parents:
diff changeset
160 if (auto ToSymbolOrErr = findSymbolByAddress(FixupValue))
anatofuz
parents:
diff changeset
161 ToSymbol = &*ToSymbolOrErr;
anatofuz
parents:
diff changeset
162 else
anatofuz
parents:
diff changeset
163 return ToSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
164 FixupValue -= ToSymbol->getAddress();
anatofuz
parents:
diff changeset
165 }
anatofuz
parents:
diff changeset
166
anatofuz
parents:
diff changeset
167 MachOARM64RelocationKind DeltaKind;
anatofuz
parents:
diff changeset
168 Symbol *TargetSymbol;
anatofuz
parents:
diff changeset
169 uint64_t Addend;
anatofuz
parents:
diff changeset
170 if (&BlockToFix == &FromSymbol->getAddressable()) {
anatofuz
parents:
diff changeset
171 TargetSymbol = ToSymbol;
anatofuz
parents:
diff changeset
172 DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
anatofuz
parents:
diff changeset
173 Addend = FixupValue + (FixupAddress - FromSymbol->getAddress());
anatofuz
parents:
diff changeset
174 // FIXME: handle extern 'from'.
anatofuz
parents:
diff changeset
175 } else if (&BlockToFix == &ToSymbol->getAddressable()) {
anatofuz
parents:
diff changeset
176 TargetSymbol = &*FromSymbol;
anatofuz
parents:
diff changeset
177 DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
anatofuz
parents:
diff changeset
178 Addend = FixupValue - (FixupAddress - ToSymbol->getAddress());
anatofuz
parents:
diff changeset
179 } else {
anatofuz
parents:
diff changeset
180 // BlockToFix was neither FromSymbol nor ToSymbol.
anatofuz
parents:
diff changeset
181 return make_error<JITLinkError>("SUBTRACTOR relocation must fix up "
anatofuz
parents:
diff changeset
182 "either 'A' or 'B' (or a symbol in one "
anatofuz
parents:
diff changeset
183 "of their alt-entry groups)");
anatofuz
parents:
diff changeset
184 }
anatofuz
parents:
diff changeset
185
anatofuz
parents:
diff changeset
186 return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
anatofuz
parents:
diff changeset
187 }
anatofuz
parents:
diff changeset
188
anatofuz
parents:
diff changeset
189 Error addRelocations() override {
anatofuz
parents:
diff changeset
190 using namespace support;
anatofuz
parents:
diff changeset
191 auto &Obj = getObject();
anatofuz
parents:
diff changeset
192
anatofuz
parents:
diff changeset
193 for (auto &S : Obj.sections()) {
anatofuz
parents:
diff changeset
194
anatofuz
parents:
diff changeset
195 JITTargetAddress SectionAddress = S.getAddress();
anatofuz
parents:
diff changeset
196
anatofuz
parents:
diff changeset
197 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
anatofuz
parents:
diff changeset
198 RelItr != RelEnd; ++RelItr) {
anatofuz
parents:
diff changeset
199
anatofuz
parents:
diff changeset
200 MachO::relocation_info RI = getRelocationInfo(RelItr);
anatofuz
parents:
diff changeset
201
anatofuz
parents:
diff changeset
202 // Sanity check the relocation kind.
anatofuz
parents:
diff changeset
203 auto Kind = getRelocationKind(RI);
anatofuz
parents:
diff changeset
204 if (!Kind)
anatofuz
parents:
diff changeset
205 return Kind.takeError();
anatofuz
parents:
diff changeset
206
anatofuz
parents:
diff changeset
207 // Find the address of the value to fix up.
anatofuz
parents:
diff changeset
208 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
anatofuz
parents:
diff changeset
209
anatofuz
parents:
diff changeset
210 LLVM_DEBUG({
anatofuz
parents:
diff changeset
211 dbgs() << "Processing " << getMachOARM64RelocationKindName(*Kind)
anatofuz
parents:
diff changeset
212 << " relocation at " << format("0x%016" PRIx64, FixupAddress)
anatofuz
parents:
diff changeset
213 << "\n";
anatofuz
parents:
diff changeset
214 });
anatofuz
parents:
diff changeset
215
anatofuz
parents:
diff changeset
216 // Find the block that the fixup points to.
anatofuz
parents:
diff changeset
217 Block *BlockToFix = nullptr;
anatofuz
parents:
diff changeset
218 {
anatofuz
parents:
diff changeset
219 auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress);
anatofuz
parents:
diff changeset
220 if (!SymbolToFixOrErr)
anatofuz
parents:
diff changeset
221 return SymbolToFixOrErr.takeError();
anatofuz
parents:
diff changeset
222 BlockToFix = &SymbolToFixOrErr->getBlock();
anatofuz
parents:
diff changeset
223 }
anatofuz
parents:
diff changeset
224
anatofuz
parents:
diff changeset
225 if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) >
anatofuz
parents:
diff changeset
226 BlockToFix->getAddress() + BlockToFix->getContent().size())
anatofuz
parents:
diff changeset
227 return make_error<JITLinkError>(
anatofuz
parents:
diff changeset
228 "Relocation content extends past end of fixup block");
anatofuz
parents:
diff changeset
229
anatofuz
parents:
diff changeset
230 // Get a pointer to the fixup content.
anatofuz
parents:
diff changeset
231 const char *FixupContent = BlockToFix->getContent().data() +
anatofuz
parents:
diff changeset
232 (FixupAddress - BlockToFix->getAddress());
anatofuz
parents:
diff changeset
233
anatofuz
parents:
diff changeset
234 // The target symbol and addend will be populated by the switch below.
anatofuz
parents:
diff changeset
235 Symbol *TargetSymbol = nullptr;
anatofuz
parents:
diff changeset
236 uint64_t Addend = 0;
anatofuz
parents:
diff changeset
237
anatofuz
parents:
diff changeset
238 if (*Kind == PairedAddend) {
anatofuz
parents:
diff changeset
239 // If this is an Addend relocation then process it and move to the
anatofuz
parents:
diff changeset
240 // paired reloc.
anatofuz
parents:
diff changeset
241
anatofuz
parents:
diff changeset
242 Addend = RI.r_symbolnum;
anatofuz
parents:
diff changeset
243
anatofuz
parents:
diff changeset
244 if (RelItr == RelEnd)
anatofuz
parents:
diff changeset
245 return make_error<JITLinkError>("Unpaired Addend reloc at " +
anatofuz
parents:
diff changeset
246 formatv("{0:x16}", FixupAddress));
anatofuz
parents:
diff changeset
247 ++RelItr;
anatofuz
parents:
diff changeset
248 RI = getRelocationInfo(RelItr);
anatofuz
parents:
diff changeset
249
anatofuz
parents:
diff changeset
250 Kind = getRelocationKind(RI);
anatofuz
parents:
diff changeset
251 if (!Kind)
anatofuz
parents:
diff changeset
252 return Kind.takeError();
anatofuz
parents:
diff changeset
253
anatofuz
parents:
diff changeset
254 if (*Kind != Branch26 && *Kind != Page21 && *Kind != PageOffset12)
anatofuz
parents:
diff changeset
255 return make_error<JITLinkError>(
anatofuz
parents:
diff changeset
256 "Invalid relocation pair: Addend + " +
anatofuz
parents:
diff changeset
257 getMachOARM64RelocationKindName(*Kind));
anatofuz
parents:
diff changeset
258 else
anatofuz
parents:
diff changeset
259 LLVM_DEBUG({
anatofuz
parents:
diff changeset
260 dbgs() << " pair is " << getMachOARM64RelocationKindName(*Kind)
anatofuz
parents:
diff changeset
261 << "`\n";
anatofuz
parents:
diff changeset
262 });
anatofuz
parents:
diff changeset
263
anatofuz
parents:
diff changeset
264 // Find the address of the value to fix up.
anatofuz
parents:
diff changeset
265 JITTargetAddress PairedFixupAddress =
anatofuz
parents:
diff changeset
266 SectionAddress + (uint32_t)RI.r_address;
anatofuz
parents:
diff changeset
267 if (PairedFixupAddress != FixupAddress)
anatofuz
parents:
diff changeset
268 return make_error<JITLinkError>("Paired relocation points at "
anatofuz
parents:
diff changeset
269 "different target");
anatofuz
parents:
diff changeset
270 }
anatofuz
parents:
diff changeset
271
anatofuz
parents:
diff changeset
272 switch (*Kind) {
anatofuz
parents:
diff changeset
273 case Branch26: {
anatofuz
parents:
diff changeset
274 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
275 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
276 else
anatofuz
parents:
diff changeset
277 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
278 uint32_t Instr = *(const ulittle32_t *)FixupContent;
anatofuz
parents:
diff changeset
279 if ((Instr & 0x7fffffff) != 0x14000000)
anatofuz
parents:
diff changeset
280 return make_error<JITLinkError>("BRANCH26 target is not a B or BL "
anatofuz
parents:
diff changeset
281 "instruction with a zero addend");
anatofuz
parents:
diff changeset
282 break;
anatofuz
parents:
diff changeset
283 }
anatofuz
parents:
diff changeset
284 case Pointer32:
anatofuz
parents:
diff changeset
285 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
286 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
287 else
anatofuz
parents:
diff changeset
288 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
289 Addend = *(const ulittle32_t *)FixupContent;
anatofuz
parents:
diff changeset
290 break;
anatofuz
parents:
diff changeset
291 case Pointer64:
anatofuz
parents:
diff changeset
292 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
293 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
294 else
anatofuz
parents:
diff changeset
295 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
296 Addend = *(const ulittle64_t *)FixupContent;
anatofuz
parents:
diff changeset
297 break;
anatofuz
parents:
diff changeset
298 case Pointer64Anon: {
anatofuz
parents:
diff changeset
299 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
anatofuz
parents:
diff changeset
300 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
anatofuz
parents:
diff changeset
301 TargetSymbol = &*TargetSymbolOrErr;
anatofuz
parents:
diff changeset
302 else
anatofuz
parents:
diff changeset
303 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
304 Addend = TargetAddress - TargetSymbol->getAddress();
anatofuz
parents:
diff changeset
305 break;
anatofuz
parents:
diff changeset
306 }
anatofuz
parents:
diff changeset
307 case Page21:
anatofuz
parents:
diff changeset
308 case GOTPage21: {
anatofuz
parents:
diff changeset
309 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
310 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
311 else
anatofuz
parents:
diff changeset
312 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
313 uint32_t Instr = *(const ulittle32_t *)FixupContent;
anatofuz
parents:
diff changeset
314 if ((Instr & 0xffffffe0) != 0x90000000)
anatofuz
parents:
diff changeset
315 return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an "
anatofuz
parents:
diff changeset
316 "ADRP instruction with a zero "
anatofuz
parents:
diff changeset
317 "addend");
anatofuz
parents:
diff changeset
318 break;
anatofuz
parents:
diff changeset
319 }
anatofuz
parents:
diff changeset
320 case PageOffset12: {
anatofuz
parents:
diff changeset
321 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
322 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
323 else
anatofuz
parents:
diff changeset
324 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
325 break;
anatofuz
parents:
diff changeset
326 }
anatofuz
parents:
diff changeset
327 case GOTPageOffset12: {
anatofuz
parents:
diff changeset
328 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
329 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
330 else
anatofuz
parents:
diff changeset
331 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
332 uint32_t Instr = *(const ulittle32_t *)FixupContent;
anatofuz
parents:
diff changeset
333 if ((Instr & 0xfffffc00) != 0xf9400000)
anatofuz
parents:
diff changeset
334 return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR "
anatofuz
parents:
diff changeset
335 "immediate instruction with a zero "
anatofuz
parents:
diff changeset
336 "addend");
anatofuz
parents:
diff changeset
337 break;
anatofuz
parents:
diff changeset
338 }
anatofuz
parents:
diff changeset
339 case PointerToGOT:
anatofuz
parents:
diff changeset
340 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
anatofuz
parents:
diff changeset
341 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
anatofuz
parents:
diff changeset
342 else
anatofuz
parents:
diff changeset
343 return TargetSymbolOrErr.takeError();
anatofuz
parents:
diff changeset
344 break;
anatofuz
parents:
diff changeset
345 case Delta32:
anatofuz
parents:
diff changeset
346 case Delta64: {
anatofuz
parents:
diff changeset
347 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
anatofuz
parents:
diff changeset
348 // parsePairRelocation handles the paired reloc, and returns the
anatofuz
parents:
diff changeset
349 // edge kind to be used (either Delta32/Delta64, or
anatofuz
parents:
diff changeset
350 // NegDelta32/NegDelta64, depending on the direction of the
anatofuz
parents:
diff changeset
351 // subtraction) along with the addend.
anatofuz
parents:
diff changeset
352 auto PairInfo =
anatofuz
parents:
diff changeset
353 parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress,
anatofuz
parents:
diff changeset
354 FixupContent, ++RelItr, RelEnd);
anatofuz
parents:
diff changeset
355 if (!PairInfo)
anatofuz
parents:
diff changeset
356 return PairInfo.takeError();
anatofuz
parents:
diff changeset
357 std::tie(*Kind, TargetSymbol, Addend) = *PairInfo;
anatofuz
parents:
diff changeset
358 assert(TargetSymbol && "No target symbol from parsePairRelocation?");
anatofuz
parents:
diff changeset
359 break;
anatofuz
parents:
diff changeset
360 }
anatofuz
parents:
diff changeset
361 default:
anatofuz
parents:
diff changeset
362 llvm_unreachable("Special relocation kind should not appear in "
anatofuz
parents:
diff changeset
363 "mach-o file");
anatofuz
parents:
diff changeset
364 }
anatofuz
parents:
diff changeset
365
anatofuz
parents:
diff changeset
366 LLVM_DEBUG({
anatofuz
parents:
diff changeset
367 Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
anatofuz
parents:
diff changeset
368 Addend);
anatofuz
parents:
diff changeset
369 printEdge(dbgs(), *BlockToFix, GE,
anatofuz
parents:
diff changeset
370 getMachOARM64RelocationKindName(*Kind));
anatofuz
parents:
diff changeset
371 dbgs() << "\n";
anatofuz
parents:
diff changeset
372 });
anatofuz
parents:
diff changeset
373 BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
anatofuz
parents:
diff changeset
374 *TargetSymbol, Addend);
anatofuz
parents:
diff changeset
375 }
anatofuz
parents:
diff changeset
376 }
anatofuz
parents:
diff changeset
377 return Error::success();
anatofuz
parents:
diff changeset
378 }
anatofuz
parents:
diff changeset
379
anatofuz
parents:
diff changeset
380 unsigned NumSymbols = 0;
anatofuz
parents:
diff changeset
381 };
anatofuz
parents:
diff changeset
382
anatofuz
parents:
diff changeset
383 class MachO_arm64_GOTAndStubsBuilder
anatofuz
parents:
diff changeset
384 : public BasicGOTAndStubsBuilder<MachO_arm64_GOTAndStubsBuilder> {
anatofuz
parents:
diff changeset
385 public:
anatofuz
parents:
diff changeset
386 MachO_arm64_GOTAndStubsBuilder(LinkGraph &G)
anatofuz
parents:
diff changeset
387 : BasicGOTAndStubsBuilder<MachO_arm64_GOTAndStubsBuilder>(G) {}
anatofuz
parents:
diff changeset
388
anatofuz
parents:
diff changeset
389 bool isGOTEdge(Edge &E) const {
anatofuz
parents:
diff changeset
390 return E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
anatofuz
parents:
diff changeset
391 E.getKind() == PointerToGOT;
anatofuz
parents:
diff changeset
392 }
anatofuz
parents:
diff changeset
393
anatofuz
parents:
diff changeset
394 Symbol &createGOTEntry(Symbol &Target) {
anatofuz
parents:
diff changeset
395 auto &GOTEntryBlock = G.createContentBlock(
anatofuz
parents:
diff changeset
396 getGOTSection(), getGOTEntryBlockContent(), 0, 8, 0);
anatofuz
parents:
diff changeset
397 GOTEntryBlock.addEdge(Pointer64, 0, Target, 0);
anatofuz
parents:
diff changeset
398 return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
anatofuz
parents:
diff changeset
399 }
anatofuz
parents:
diff changeset
400
anatofuz
parents:
diff changeset
401 void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
anatofuz
parents:
diff changeset
402 if (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12) {
anatofuz
parents:
diff changeset
403 // Update the target, but leave the edge addend as-is.
anatofuz
parents:
diff changeset
404 E.setTarget(GOTEntry);
anatofuz
parents:
diff changeset
405 } else if (E.getKind() == PointerToGOT) {
anatofuz
parents:
diff changeset
406 E.setTarget(GOTEntry);
anatofuz
parents:
diff changeset
407 E.setKind(Delta32);
anatofuz
parents:
diff changeset
408 } else
anatofuz
parents:
diff changeset
409 llvm_unreachable("Not a GOT edge?");
anatofuz
parents:
diff changeset
410 }
anatofuz
parents:
diff changeset
411
anatofuz
parents:
diff changeset
412 bool isExternalBranchEdge(Edge &E) {
anatofuz
parents:
diff changeset
413 return E.getKind() == Branch26 && !E.getTarget().isDefined();
anatofuz
parents:
diff changeset
414 }
anatofuz
parents:
diff changeset
415
anatofuz
parents:
diff changeset
416 Symbol &createStub(Symbol &Target) {
anatofuz
parents:
diff changeset
417 auto &StubContentBlock =
anatofuz
parents:
diff changeset
418 G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
anatofuz
parents:
diff changeset
419 // Re-use GOT entries for stub targets.
anatofuz
parents:
diff changeset
420 auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
anatofuz
parents:
diff changeset
421 StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0);
anatofuz
parents:
diff changeset
422 return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false);
anatofuz
parents:
diff changeset
423 }
anatofuz
parents:
diff changeset
424
anatofuz
parents:
diff changeset
425 void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
anatofuz
parents:
diff changeset
426 assert(E.getKind() == Branch26 && "Not a Branch32 edge?");
anatofuz
parents:
diff changeset
427 assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
anatofuz
parents:
diff changeset
428 E.setTarget(Stub);
anatofuz
parents:
diff changeset
429 }
anatofuz
parents:
diff changeset
430
anatofuz
parents:
diff changeset
431 private:
anatofuz
parents:
diff changeset
432 Section &getGOTSection() {
anatofuz
parents:
diff changeset
433 if (!GOTSection)
anatofuz
parents:
diff changeset
434 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
anatofuz
parents:
diff changeset
435 return *GOTSection;
anatofuz
parents:
diff changeset
436 }
anatofuz
parents:
diff changeset
437
anatofuz
parents:
diff changeset
438 Section &getStubsSection() {
anatofuz
parents:
diff changeset
439 if (!StubsSection) {
anatofuz
parents:
diff changeset
440 auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
anatofuz
parents:
diff changeset
441 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
anatofuz
parents:
diff changeset
442 StubsSection = &G.createSection("$__STUBS", StubsProt);
anatofuz
parents:
diff changeset
443 }
anatofuz
parents:
diff changeset
444 return *StubsSection;
anatofuz
parents:
diff changeset
445 }
anatofuz
parents:
diff changeset
446
anatofuz
parents:
diff changeset
447 StringRef getGOTEntryBlockContent() {
anatofuz
parents:
diff changeset
448 return StringRef(reinterpret_cast<const char *>(NullGOTEntryContent),
anatofuz
parents:
diff changeset
449 sizeof(NullGOTEntryContent));
anatofuz
parents:
diff changeset
450 }
anatofuz
parents:
diff changeset
451
anatofuz
parents:
diff changeset
452 StringRef getStubBlockContent() {
anatofuz
parents:
diff changeset
453 return StringRef(reinterpret_cast<const char *>(StubContent),
anatofuz
parents:
diff changeset
454 sizeof(StubContent));
anatofuz
parents:
diff changeset
455 }
anatofuz
parents:
diff changeset
456
anatofuz
parents:
diff changeset
457 static const uint8_t NullGOTEntryContent[8];
anatofuz
parents:
diff changeset
458 static const uint8_t StubContent[8];
anatofuz
parents:
diff changeset
459 Section *GOTSection = nullptr;
anatofuz
parents:
diff changeset
460 Section *StubsSection = nullptr;
anatofuz
parents:
diff changeset
461 };
anatofuz
parents:
diff changeset
462
anatofuz
parents:
diff changeset
463 const uint8_t MachO_arm64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
anatofuz
parents:
diff changeset
464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
anatofuz
parents:
diff changeset
465 const uint8_t MachO_arm64_GOTAndStubsBuilder::StubContent[8] = {
anatofuz
parents:
diff changeset
466 0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
anatofuz
parents:
diff changeset
467 0x00, 0x02, 0x1f, 0xd6 // BR x16
anatofuz
parents:
diff changeset
468 };
anatofuz
parents:
diff changeset
469
anatofuz
parents:
diff changeset
470 } // namespace
anatofuz
parents:
diff changeset
471
anatofuz
parents:
diff changeset
472 namespace llvm {
anatofuz
parents:
diff changeset
473 namespace jitlink {
anatofuz
parents:
diff changeset
474
anatofuz
parents:
diff changeset
475 class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
anatofuz
parents:
diff changeset
476 friend class JITLinker<MachOJITLinker_arm64>;
anatofuz
parents:
diff changeset
477
anatofuz
parents:
diff changeset
478 public:
anatofuz
parents:
diff changeset
479 MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
anatofuz
parents:
diff changeset
480 PassConfiguration PassConfig)
anatofuz
parents:
diff changeset
481 : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
anatofuz
parents:
diff changeset
482
anatofuz
parents:
diff changeset
483 private:
anatofuz
parents:
diff changeset
484 StringRef getEdgeKindName(Edge::Kind R) const override {
anatofuz
parents:
diff changeset
485 return getMachOARM64RelocationKindName(R);
anatofuz
parents:
diff changeset
486 }
anatofuz
parents:
diff changeset
487
anatofuz
parents:
diff changeset
488 Expected<std::unique_ptr<LinkGraph>>
anatofuz
parents:
diff changeset
489 buildGraph(MemoryBufferRef ObjBuffer) override {
anatofuz
parents:
diff changeset
490 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
anatofuz
parents:
diff changeset
491 if (!MachOObj)
anatofuz
parents:
diff changeset
492 return MachOObj.takeError();
anatofuz
parents:
diff changeset
493 return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
anatofuz
parents:
diff changeset
494 }
anatofuz
parents:
diff changeset
495
anatofuz
parents:
diff changeset
496 static Error targetOutOfRangeError(const Block &B, const Edge &E) {
anatofuz
parents:
diff changeset
497 std::string ErrMsg;
anatofuz
parents:
diff changeset
498 {
anatofuz
parents:
diff changeset
499 raw_string_ostream ErrStream(ErrMsg);
anatofuz
parents:
diff changeset
500 ErrStream << "Relocation target out of range: ";
anatofuz
parents:
diff changeset
501 printEdge(ErrStream, B, E, getMachOARM64RelocationKindName(E.getKind()));
anatofuz
parents:
diff changeset
502 ErrStream << "\n";
anatofuz
parents:
diff changeset
503 }
anatofuz
parents:
diff changeset
504 return make_error<JITLinkError>(std::move(ErrMsg));
anatofuz
parents:
diff changeset
505 }
anatofuz
parents:
diff changeset
506
anatofuz
parents:
diff changeset
507 static unsigned getPageOffset12Shift(uint32_t Instr) {
anatofuz
parents:
diff changeset
508 constexpr uint32_t LDRLiteralMask = 0x3ffffc00;
anatofuz
parents:
diff changeset
509
anatofuz
parents:
diff changeset
510 // Check for a GPR LDR immediate with a zero embedded literal.
anatofuz
parents:
diff changeset
511 // If found, the top two bits contain the shift.
anatofuz
parents:
diff changeset
512 if ((Instr & LDRLiteralMask) == 0x39400000)
anatofuz
parents:
diff changeset
513 return Instr >> 30;
anatofuz
parents:
diff changeset
514
anatofuz
parents:
diff changeset
515 // Check for a Neon LDR immediate of size 64-bit or less with a zero
anatofuz
parents:
diff changeset
516 // embedded literal. If found, the top two bits contain the shift.
anatofuz
parents:
diff changeset
517 if ((Instr & LDRLiteralMask) == 0x3d400000)
anatofuz
parents:
diff changeset
518 return Instr >> 30;
anatofuz
parents:
diff changeset
519
anatofuz
parents:
diff changeset
520 // Check for a Neon LDR immediate of size 128-bit with a zero embedded
anatofuz
parents:
diff changeset
521 // literal.
anatofuz
parents:
diff changeset
522 constexpr uint32_t SizeBitsMask = 0xc0000000;
anatofuz
parents:
diff changeset
523 if ((Instr & (LDRLiteralMask | SizeBitsMask)) == 0x3dc00000)
anatofuz
parents:
diff changeset
524 return 4;
anatofuz
parents:
diff changeset
525
anatofuz
parents:
diff changeset
526 return 0;
anatofuz
parents:
diff changeset
527 }
anatofuz
parents:
diff changeset
528
anatofuz
parents:
diff changeset
529 Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
anatofuz
parents:
diff changeset
530 using namespace support;
anatofuz
parents:
diff changeset
531
anatofuz
parents:
diff changeset
532 char *FixupPtr = BlockWorkingMem + E.getOffset();
anatofuz
parents:
diff changeset
533 JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
anatofuz
parents:
diff changeset
534
anatofuz
parents:
diff changeset
535 switch (E.getKind()) {
anatofuz
parents:
diff changeset
536 case Branch26: {
anatofuz
parents:
diff changeset
537 assert((FixupAddress & 0x3) == 0 && "Branch-inst is not 32-bit aligned");
anatofuz
parents:
diff changeset
538
anatofuz
parents:
diff changeset
539 int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
anatofuz
parents:
diff changeset
540
anatofuz
parents:
diff changeset
541 if (static_cast<uint64_t>(Value) & 0x3)
anatofuz
parents:
diff changeset
542 return make_error<JITLinkError>("Branch26 target is not 32-bit "
anatofuz
parents:
diff changeset
543 "aligned");
anatofuz
parents:
diff changeset
544
anatofuz
parents:
diff changeset
545 if (Value < -(1 << 27) || Value > ((1 << 27) - 1))
anatofuz
parents:
diff changeset
546 return targetOutOfRangeError(B, E);
anatofuz
parents:
diff changeset
547
anatofuz
parents:
diff changeset
548 uint32_t RawInstr = *(little32_t *)FixupPtr;
anatofuz
parents:
diff changeset
549 assert((RawInstr & 0x7fffffff) == 0x14000000 &&
anatofuz
parents:
diff changeset
550 "RawInstr isn't a B or BR immediate instruction");
anatofuz
parents:
diff changeset
551 uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2;
anatofuz
parents:
diff changeset
552 uint32_t FixedInstr = RawInstr | Imm;
anatofuz
parents:
diff changeset
553 *(little32_t *)FixupPtr = FixedInstr;
anatofuz
parents:
diff changeset
554 break;
anatofuz
parents:
diff changeset
555 }
anatofuz
parents:
diff changeset
556 case Pointer32: {
anatofuz
parents:
diff changeset
557 uint64_t Value = E.getTarget().getAddress() + E.getAddend();
anatofuz
parents:
diff changeset
558 if (Value > std::numeric_limits<uint32_t>::max())
anatofuz
parents:
diff changeset
559 return targetOutOfRangeError(B, E);
anatofuz
parents:
diff changeset
560 *(ulittle32_t *)FixupPtr = Value;
anatofuz
parents:
diff changeset
561 break;
anatofuz
parents:
diff changeset
562 }
anatofuz
parents:
diff changeset
563 case Pointer64: {
anatofuz
parents:
diff changeset
564 uint64_t Value = E.getTarget().getAddress() + E.getAddend();
anatofuz
parents:
diff changeset
565 *(ulittle64_t *)FixupPtr = Value;
anatofuz
parents:
diff changeset
566 break;
anatofuz
parents:
diff changeset
567 }
anatofuz
parents:
diff changeset
568 case Page21:
anatofuz
parents:
diff changeset
569 case GOTPage21: {
anatofuz
parents:
diff changeset
570 assert(E.getAddend() == 0 && "PAGE21/GOTPAGE21 with non-zero addend");
anatofuz
parents:
diff changeset
571 uint64_t TargetPage =
anatofuz
parents:
diff changeset
572 E.getTarget().getAddress() & ~static_cast<uint64_t>(4096 - 1);
anatofuz
parents:
diff changeset
573 uint64_t PCPage = B.getAddress() & ~static_cast<uint64_t>(4096 - 1);
anatofuz
parents:
diff changeset
574
anatofuz
parents:
diff changeset
575 int64_t PageDelta = TargetPage - PCPage;
anatofuz
parents:
diff changeset
576 if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1))
anatofuz
parents:
diff changeset
577 return targetOutOfRangeError(B, E);
anatofuz
parents:
diff changeset
578
anatofuz
parents:
diff changeset
579 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
anatofuz
parents:
diff changeset
580 assert((RawInstr & 0xffffffe0) == 0x90000000 &&
anatofuz
parents:
diff changeset
581 "RawInstr isn't an ADRP instruction");
anatofuz
parents:
diff changeset
582 uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3;
anatofuz
parents:
diff changeset
583 uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff;
anatofuz
parents:
diff changeset
584 uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5);
anatofuz
parents:
diff changeset
585 *(ulittle32_t *)FixupPtr = FixedInstr;
anatofuz
parents:
diff changeset
586 break;
anatofuz
parents:
diff changeset
587 }
anatofuz
parents:
diff changeset
588 case PageOffset12: {
anatofuz
parents:
diff changeset
589 assert(E.getAddend() == 0 && "PAGEOFF12 with non-zero addend");
anatofuz
parents:
diff changeset
590 uint64_t TargetOffset = E.getTarget().getAddress() & 0xfff;
anatofuz
parents:
diff changeset
591
anatofuz
parents:
diff changeset
592 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
anatofuz
parents:
diff changeset
593 unsigned ImmShift = getPageOffset12Shift(RawInstr);
anatofuz
parents:
diff changeset
594
anatofuz
parents:
diff changeset
595 if (TargetOffset & ((1 << ImmShift) - 1))
anatofuz
parents:
diff changeset
596 return make_error<JITLinkError>("PAGEOFF12 target is not aligned");
anatofuz
parents:
diff changeset
597
anatofuz
parents:
diff changeset
598 uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10;
anatofuz
parents:
diff changeset
599 uint32_t FixedInstr = RawInstr | EncodedImm;
anatofuz
parents:
diff changeset
600 *(ulittle32_t *)FixupPtr = FixedInstr;
anatofuz
parents:
diff changeset
601 break;
anatofuz
parents:
diff changeset
602 }
anatofuz
parents:
diff changeset
603 case GOTPageOffset12: {
anatofuz
parents:
diff changeset
604 assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend");
anatofuz
parents:
diff changeset
605
anatofuz
parents:
diff changeset
606 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
anatofuz
parents:
diff changeset
607 assert((RawInstr & 0xfffffc00) == 0xf9400000 &&
anatofuz
parents:
diff changeset
608 "RawInstr isn't a 64-bit LDR immediate");
anatofuz
parents:
diff changeset
609
anatofuz
parents:
diff changeset
610 uint32_t TargetOffset = E.getTarget().getAddress() & 0xfff;
anatofuz
parents:
diff changeset
611 assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned");
anatofuz
parents:
diff changeset
612 uint32_t EncodedImm = (TargetOffset >> 3) << 10;
anatofuz
parents:
diff changeset
613 uint32_t FixedInstr = RawInstr | EncodedImm;
anatofuz
parents:
diff changeset
614 *(ulittle32_t *)FixupPtr = FixedInstr;
anatofuz
parents:
diff changeset
615 break;
anatofuz
parents:
diff changeset
616 }
anatofuz
parents:
diff changeset
617 case LDRLiteral19: {
anatofuz
parents:
diff changeset
618 assert((FixupAddress & 0x3) == 0 && "LDR is not 32-bit aligned");
anatofuz
parents:
diff changeset
619 assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend");
anatofuz
parents:
diff changeset
620 uint32_t RawInstr = *(ulittle32_t *)FixupPtr;
anatofuz
parents:
diff changeset
621 assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal");
anatofuz
parents:
diff changeset
622 int64_t Delta = E.getTarget().getAddress() - FixupAddress;
anatofuz
parents:
diff changeset
623 if (Delta & 0x3)
anatofuz
parents:
diff changeset
624 return make_error<JITLinkError>("LDR literal target is not 32-bit "
anatofuz
parents:
diff changeset
625 "aligned");
anatofuz
parents:
diff changeset
626 if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1))
anatofuz
parents:
diff changeset
627 return targetOutOfRangeError(B, E);
anatofuz
parents:
diff changeset
628
anatofuz
parents:
diff changeset
629 uint32_t EncodedImm = (static_cast<uint32_t>(Delta) >> 2) << 5;
anatofuz
parents:
diff changeset
630 uint32_t FixedInstr = RawInstr | EncodedImm;
anatofuz
parents:
diff changeset
631 *(ulittle32_t *)FixupPtr = FixedInstr;
anatofuz
parents:
diff changeset
632 break;
anatofuz
parents:
diff changeset
633 }
anatofuz
parents:
diff changeset
634 case Delta32:
anatofuz
parents:
diff changeset
635 case Delta64:
anatofuz
parents:
diff changeset
636 case NegDelta32:
anatofuz
parents:
diff changeset
637 case NegDelta64: {
anatofuz
parents:
diff changeset
638 int64_t Value;
anatofuz
parents:
diff changeset
639 if (E.getKind() == Delta32 || E.getKind() == Delta64)
anatofuz
parents:
diff changeset
640 Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
anatofuz
parents:
diff changeset
641 else
anatofuz
parents:
diff changeset
642 Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
anatofuz
parents:
diff changeset
643
anatofuz
parents:
diff changeset
644 if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
anatofuz
parents:
diff changeset
645 if (Value < std::numeric_limits<int32_t>::min() ||
anatofuz
parents:
diff changeset
646 Value > std::numeric_limits<int32_t>::max())
anatofuz
parents:
diff changeset
647 return targetOutOfRangeError(B, E);
anatofuz
parents:
diff changeset
648 *(little32_t *)FixupPtr = Value;
anatofuz
parents:
diff changeset
649 } else
anatofuz
parents:
diff changeset
650 *(little64_t *)FixupPtr = Value;
anatofuz
parents:
diff changeset
651 break;
anatofuz
parents:
diff changeset
652 }
anatofuz
parents:
diff changeset
653 default:
anatofuz
parents:
diff changeset
654 llvm_unreachable("Unrecognized edge kind");
anatofuz
parents:
diff changeset
655 }
anatofuz
parents:
diff changeset
656
anatofuz
parents:
diff changeset
657 return Error::success();
anatofuz
parents:
diff changeset
658 }
anatofuz
parents:
diff changeset
659
anatofuz
parents:
diff changeset
660 uint64_t NullValue = 0;
anatofuz
parents:
diff changeset
661 };
anatofuz
parents:
diff changeset
662
anatofuz
parents:
diff changeset
663 void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) {
anatofuz
parents:
diff changeset
664 PassConfiguration Config;
anatofuz
parents:
diff changeset
665 Triple TT("arm64-apple-ios");
anatofuz
parents:
diff changeset
666
anatofuz
parents:
diff changeset
667 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
anatofuz
parents:
diff changeset
668 // Add a mark-live pass.
anatofuz
parents:
diff changeset
669 if (auto MarkLive = Ctx->getMarkLivePass(TT))
anatofuz
parents:
diff changeset
670 Config.PrePrunePasses.push_back(std::move(MarkLive));
anatofuz
parents:
diff changeset
671 else
anatofuz
parents:
diff changeset
672 Config.PrePrunePasses.push_back(markAllSymbolsLive);
anatofuz
parents:
diff changeset
673
anatofuz
parents:
diff changeset
674 // Add an in-place GOT/Stubs pass.
anatofuz
parents:
diff changeset
675 Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
anatofuz
parents:
diff changeset
676 MachO_arm64_GOTAndStubsBuilder(G).run();
anatofuz
parents:
diff changeset
677 return Error::success();
anatofuz
parents:
diff changeset
678 });
anatofuz
parents:
diff changeset
679 }
anatofuz
parents:
diff changeset
680
anatofuz
parents:
diff changeset
681 if (auto Err = Ctx->modifyPassConfig(TT, Config))
anatofuz
parents:
diff changeset
682 return Ctx->notifyFailed(std::move(Err));
anatofuz
parents:
diff changeset
683
anatofuz
parents:
diff changeset
684 // Construct a JITLinker and run the link function.
anatofuz
parents:
diff changeset
685 MachOJITLinker_arm64::link(std::move(Ctx), std::move(Config));
anatofuz
parents:
diff changeset
686 }
anatofuz
parents:
diff changeset
687
anatofuz
parents:
diff changeset
688 StringRef getMachOARM64RelocationKindName(Edge::Kind R) {
anatofuz
parents:
diff changeset
689 switch (R) {
anatofuz
parents:
diff changeset
690 case Branch26:
anatofuz
parents:
diff changeset
691 return "Branch26";
anatofuz
parents:
diff changeset
692 case Pointer64:
anatofuz
parents:
diff changeset
693 return "Pointer64";
anatofuz
parents:
diff changeset
694 case Pointer64Anon:
anatofuz
parents:
diff changeset
695 return "Pointer64Anon";
anatofuz
parents:
diff changeset
696 case Page21:
anatofuz
parents:
diff changeset
697 return "Page21";
anatofuz
parents:
diff changeset
698 case PageOffset12:
anatofuz
parents:
diff changeset
699 return "PageOffset12";
anatofuz
parents:
diff changeset
700 case GOTPage21:
anatofuz
parents:
diff changeset
701 return "GOTPage21";
anatofuz
parents:
diff changeset
702 case GOTPageOffset12:
anatofuz
parents:
diff changeset
703 return "GOTPageOffset12";
anatofuz
parents:
diff changeset
704 case PointerToGOT:
anatofuz
parents:
diff changeset
705 return "PointerToGOT";
anatofuz
parents:
diff changeset
706 case PairedAddend:
anatofuz
parents:
diff changeset
707 return "PairedAddend";
anatofuz
parents:
diff changeset
708 case LDRLiteral19:
anatofuz
parents:
diff changeset
709 return "LDRLiteral19";
anatofuz
parents:
diff changeset
710 case Delta32:
anatofuz
parents:
diff changeset
711 return "Delta32";
anatofuz
parents:
diff changeset
712 case Delta64:
anatofuz
parents:
diff changeset
713 return "Delta64";
anatofuz
parents:
diff changeset
714 case NegDelta32:
anatofuz
parents:
diff changeset
715 return "NegDelta32";
anatofuz
parents:
diff changeset
716 case NegDelta64:
anatofuz
parents:
diff changeset
717 return "NegDelta64";
anatofuz
parents:
diff changeset
718 default:
anatofuz
parents:
diff changeset
719 return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
anatofuz
parents:
diff changeset
720 }
anatofuz
parents:
diff changeset
721 }
anatofuz
parents:
diff changeset
722
anatofuz
parents:
diff changeset
723 } // end namespace jitlink
anatofuz
parents:
diff changeset
724 } // end namespace llvm