1 //===- lib/FileFormat/MachO/ArchHandler_arm64.cpp -------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "ArchHandler.h"
10 #include "Atoms.h"
11 #include "MachONormalizedFileBinaryUtils.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/ADT/Triple.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/Format.h"
18
19 using namespace llvm::MachO;
20 using namespace lld::mach_o::normalized;
21
22 namespace lld {
23 namespace mach_o {
24
25 using llvm::support::ulittle32_t;
26 using llvm::support::ulittle64_t;
27
28 using llvm::support::little32_t;
29 using llvm::support::little64_t;
30
31 class ArchHandler_arm64 : public ArchHandler {
32 public:
33 ArchHandler_arm64() = default;
34 ~ArchHandler_arm64() override = default;
35
kindStrings()36 const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
37
kindArch()38 Reference::KindArch kindArch() override {
39 return Reference::KindArch::AArch64;
40 }
41
42 /// Used by GOTPass to locate GOT References
isGOTAccess(const Reference & ref,bool & canBypassGOT)43 bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
44 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
45 return false;
46 assert(ref.kindArch() == Reference::KindArch::AArch64);
47 switch (ref.kindValue()) {
48 case gotPage21:
49 case gotOffset12:
50 canBypassGOT = true;
51 return true;
52 case delta32ToGOT:
53 case unwindCIEToPersonalityFunction:
54 case imageOffsetGot:
55 canBypassGOT = false;
56 return true;
57 default:
58 return false;
59 }
60 }
61
62 /// Used by GOTPass to update GOT References.
updateReferenceToGOT(const Reference * ref,bool targetNowGOT)63 void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
64 // If GOT slot was instantiated, transform:
65 // gotPage21/gotOffset12 -> page21/offset12scale8
66 // If GOT slot optimized away, transform:
67 // gotPage21/gotOffset12 -> page21/addOffset12
68 assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
69 assert(ref->kindArch() == Reference::KindArch::AArch64);
70 switch (ref->kindValue()) {
71 case gotPage21:
72 const_cast<Reference *>(ref)->setKindValue(page21);
73 break;
74 case gotOffset12:
75 const_cast<Reference *>(ref)->setKindValue(targetNowGOT ?
76 offset12scale8 : addOffset12);
77 break;
78 case delta32ToGOT:
79 const_cast<Reference *>(ref)->setKindValue(delta32);
80 break;
81 case imageOffsetGot:
82 const_cast<Reference *>(ref)->setKindValue(imageOffset);
83 break;
84 default:
85 llvm_unreachable("Not a GOT reference");
86 }
87 }
88
stubInfo()89 const StubInfo &stubInfo() override { return _sStubInfo; }
90
91 bool isCallSite(const Reference &) override;
isNonCallBranch(const Reference &)92 bool isNonCallBranch(const Reference &) override {
93 return false;
94 }
95
96 bool isPointer(const Reference &) override;
97 bool isPairedReloc(const normalized::Relocation &) override;
98
needsCompactUnwind()99 bool needsCompactUnwind() override {
100 return true;
101 }
imageOffsetKind()102 Reference::KindValue imageOffsetKind() override {
103 return imageOffset;
104 }
imageOffsetKindIndirect()105 Reference::KindValue imageOffsetKindIndirect() override {
106 return imageOffsetGot;
107 }
108
unwindRefToPersonalityFunctionKind()109 Reference::KindValue unwindRefToPersonalityFunctionKind() override {
110 return unwindCIEToPersonalityFunction;
111 }
112
unwindRefToCIEKind()113 Reference::KindValue unwindRefToCIEKind() override {
114 return negDelta32;
115 }
116
unwindRefToFunctionKind()117 Reference::KindValue unwindRefToFunctionKind() override {
118 return unwindFDEToFunction;
119 }
120
unwindRefToEhFrameKind()121 Reference::KindValue unwindRefToEhFrameKind() override {
122 return unwindInfoToEhFrame;
123 }
124
pointerKind()125 Reference::KindValue pointerKind() override {
126 return pointer64;
127 }
128
lazyImmediateLocationKind()129 Reference::KindValue lazyImmediateLocationKind() override {
130 return lazyImmediateLocation;
131 }
132
dwarfCompactUnwindType()133 uint32_t dwarfCompactUnwindType() override {
134 return 0x03000000;
135 }
136
137 llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
138 const DefinedAtom *inAtom,
139 uint32_t offsetInAtom,
140 uint64_t fixupAddress, bool isBig,
141 FindAtomBySectionAndAddress atomFromAddress,
142 FindAtomBySymbolIndex atomFromSymbolIndex,
143 Reference::KindValue *kind,
144 const lld::Atom **target,
145 Reference::Addend *addend) override;
146 llvm::Error
147 getPairReferenceInfo(const normalized::Relocation &reloc1,
148 const normalized::Relocation &reloc2,
149 const DefinedAtom *inAtom,
150 uint32_t offsetInAtom,
151 uint64_t fixupAddress, bool isBig, bool scatterable,
152 FindAtomBySectionAndAddress atomFromAddress,
153 FindAtomBySymbolIndex atomFromSymbolIndex,
154 Reference::KindValue *kind,
155 const lld::Atom **target,
156 Reference::Addend *addend) override;
157
needsLocalSymbolInRelocatableFile(const DefinedAtom * atom)158 bool needsLocalSymbolInRelocatableFile(const DefinedAtom *atom) override {
159 return (atom->contentType() == DefinedAtom::typeCString);
160 }
161
162 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
163 FindAddressForAtom findAddress,
164 FindAddressForAtom findSectionAddress,
165 uint64_t imageBaseAddress,
166 llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
167
168 void appendSectionRelocations(const DefinedAtom &atom,
169 uint64_t atomSectionOffset,
170 const Reference &ref,
171 FindSymbolIndexForAtom symbolIndexForAtom,
172 FindSectionIndexForAtom sectionIndexForAtom,
173 FindAddressForAtom addressForAtom,
174 normalized::Relocations &relocs) override;
175
176 private:
177 static const Registry::KindStrings _sKindStrings[];
178 static const StubInfo _sStubInfo;
179
180 enum Arm64Kind : Reference::KindValue {
181 invalid, /// for error condition
182
183 // Kinds found in mach-o .o files:
184 branch26, /// ex: bl _foo
185 page21, /// ex: adrp x1, _foo@PAGE
186 offset12, /// ex: ldrb w0, [x1, _foo@PAGEOFF]
187 offset12scale2, /// ex: ldrs w0, [x1, _foo@PAGEOFF]
188 offset12scale4, /// ex: ldr w0, [x1, _foo@PAGEOFF]
189 offset12scale8, /// ex: ldr x0, [x1, _foo@PAGEOFF]
190 offset12scale16, /// ex: ldr q0, [x1, _foo@PAGEOFF]
191 gotPage21, /// ex: adrp x1, _foo@GOTPAGE
192 gotOffset12, /// ex: ldr w0, [x1, _foo@GOTPAGEOFF]
193 tlvPage21, /// ex: adrp x1, _foo@TLVPAGE
194 tlvOffset12, /// ex: ldr w0, [x1, _foo@TLVPAGEOFF]
195
196 pointer64, /// ex: .quad _foo
197 delta64, /// ex: .quad _foo - .
198 delta32, /// ex: .long _foo - .
199 negDelta32, /// ex: .long . - _foo
200 pointer64ToGOT, /// ex: .quad _foo@GOT
201 delta32ToGOT, /// ex: .long _foo@GOT - .
202
203 // Kinds introduced by Passes:
204 addOffset12, /// Location contains LDR to change into ADD.
205 lazyPointer, /// Location contains a lazy pointer.
206 lazyImmediateLocation, /// Location contains immediate value used in stub.
207 imageOffset, /// Location contains offset of atom in final image
208 imageOffsetGot, /// Location contains offset of GOT entry for atom in
209 /// final image (typically personality function).
210 unwindCIEToPersonalityFunction, /// Nearly delta32ToGOT, but cannot be
211 /// rematerialized in relocatable object
212 /// (yay for implicit contracts!).
213 unwindFDEToFunction, /// Nearly delta64, but cannot be rematerialized in
214 /// relocatable object (yay for implicit contracts!).
215 unwindInfoToEhFrame, /// Fix low 24 bits of compact unwind encoding to
216 /// refer to __eh_frame entry.
217 };
218
219 void applyFixupFinal(const Reference &ref, uint8_t *location,
220 uint64_t fixupAddress, uint64_t targetAddress,
221 uint64_t inAtomAddress, uint64_t imageBaseAddress,
222 FindAddressForAtom findSectionAddress);
223
224 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
225 uint64_t fixupAddress, uint64_t targetAddress,
226 uint64_t inAtomAddress, bool targetUnnamed);
227
228 // Utility functions for inspecting/updating instructions.
229 static uint32_t setDisplacementInBranch26(uint32_t instr, int32_t disp);
230 static uint32_t setDisplacementInADRP(uint32_t instr, int64_t disp);
231 static Arm64Kind offset12KindFromInstruction(uint32_t instr);
232 static uint32_t setImm12(uint32_t instr, uint32_t offset);
233 };
234
235 const Registry::KindStrings ArchHandler_arm64::_sKindStrings[] = {
236 LLD_KIND_STRING_ENTRY(invalid),
237 LLD_KIND_STRING_ENTRY(branch26),
238 LLD_KIND_STRING_ENTRY(page21),
239 LLD_KIND_STRING_ENTRY(offset12),
240 LLD_KIND_STRING_ENTRY(offset12scale2),
241 LLD_KIND_STRING_ENTRY(offset12scale4),
242 LLD_KIND_STRING_ENTRY(offset12scale8),
243 LLD_KIND_STRING_ENTRY(offset12scale16),
244 LLD_KIND_STRING_ENTRY(gotPage21),
245 LLD_KIND_STRING_ENTRY(gotOffset12),
246 LLD_KIND_STRING_ENTRY(tlvPage21),
247 LLD_KIND_STRING_ENTRY(tlvOffset12),
248 LLD_KIND_STRING_ENTRY(pointer64),
249 LLD_KIND_STRING_ENTRY(delta64),
250 LLD_KIND_STRING_ENTRY(delta32),
251 LLD_KIND_STRING_ENTRY(negDelta32),
252 LLD_KIND_STRING_ENTRY(pointer64ToGOT),
253 LLD_KIND_STRING_ENTRY(delta32ToGOT),
254
255 LLD_KIND_STRING_ENTRY(addOffset12),
256 LLD_KIND_STRING_ENTRY(lazyPointer),
257 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
258 LLD_KIND_STRING_ENTRY(imageOffset),
259 LLD_KIND_STRING_ENTRY(imageOffsetGot),
260 LLD_KIND_STRING_ENTRY(unwindCIEToPersonalityFunction),
261 LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
262 LLD_KIND_STRING_ENTRY(unwindInfoToEhFrame),
263
264 LLD_KIND_STRING_END
265 };
266
267 const ArchHandler::StubInfo ArchHandler_arm64::_sStubInfo = {
268 "dyld_stub_binder",
269
270 // Lazy pointer references
271 { Reference::KindArch::AArch64, pointer64, 0, 0 },
272 { Reference::KindArch::AArch64, lazyPointer, 0, 0 },
273
274 // GOT pointer to dyld_stub_binder
275 { Reference::KindArch::AArch64, pointer64, 0, 0 },
276
277 // arm64 code alignment 2^1
278 1,
279
280 // Stub size and code
281 12,
282 { 0x10, 0x00, 0x00, 0x90, // ADRP X16, lazy_pointer@page
283 0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16, lazy_pointer@pageoff]
284 0x00, 0x02, 0x1F, 0xD6 }, // BR X16
285 { Reference::KindArch::AArch64, page21, 0, 0 },
286 { true, offset12scale8, 4, 0 },
287
288 // Stub Helper size and code
289 12,
290 { 0x50, 0x00, 0x00, 0x18, // LDR W16, L0
291 0x00, 0x00, 0x00, 0x14, // LDR B helperhelper
292 0x00, 0x00, 0x00, 0x00 }, // L0: .long 0
293 { Reference::KindArch::AArch64, lazyImmediateLocation, 8, 0 },
294 { Reference::KindArch::AArch64, branch26, 4, 0 },
295
296 // Stub helper image cache content type
297 DefinedAtom::typeGOT,
298
299 // Stub Helper-Common size and code
300 24,
301 // Stub helper alignment
302 2,
303 { 0x11, 0x00, 0x00, 0x90, // ADRP X17, dyld_ImageLoaderCache@page
304 0x31, 0x02, 0x00, 0x91, // ADD X17, X17, dyld_ImageLoaderCache@pageoff
305 0xF0, 0x47, 0xBF, 0xA9, // STP X16/X17, [SP, #-16]!
306 0x10, 0x00, 0x00, 0x90, // ADRP X16, _fast_lazy_bind@page
307 0x10, 0x02, 0x40, 0xF9, // LDR X16, [X16,_fast_lazy_bind@pageoff]
308 0x00, 0x02, 0x1F, 0xD6 }, // BR X16
309 { Reference::KindArch::AArch64, page21, 0, 0 },
310 { true, offset12, 4, 0 },
311 { Reference::KindArch::AArch64, page21, 12, 0 },
312 { true, offset12scale8, 16, 0 }
313 };
314
isCallSite(const Reference & ref)315 bool ArchHandler_arm64::isCallSite(const Reference &ref) {
316 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
317 return false;
318 assert(ref.kindArch() == Reference::KindArch::AArch64);
319 return (ref.kindValue() == branch26);
320 }
321
isPointer(const Reference & ref)322 bool ArchHandler_arm64::isPointer(const Reference &ref) {
323 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
324 return false;
325 assert(ref.kindArch() == Reference::KindArch::AArch64);
326 Reference::KindValue kind = ref.kindValue();
327 return (kind == pointer64);
328 }
329
isPairedReloc(const Relocation & r)330 bool ArchHandler_arm64::isPairedReloc(const Relocation &r) {
331 return ((r.type == ARM64_RELOC_ADDEND) || (r.type == ARM64_RELOC_SUBTRACTOR));
332 }
333
setDisplacementInBranch26(uint32_t instr,int32_t displacement)334 uint32_t ArchHandler_arm64::setDisplacementInBranch26(uint32_t instr,
335 int32_t displacement) {
336 assert((displacement <= 134217727) && (displacement > (-134217728)) &&
337 "arm64 branch out of range");
338 return (instr & 0xFC000000) | ((uint32_t)(displacement >> 2) & 0x03FFFFFF);
339 }
340
setDisplacementInADRP(uint32_t instruction,int64_t displacement)341 uint32_t ArchHandler_arm64::setDisplacementInADRP(uint32_t instruction,
342 int64_t displacement) {
343 assert((displacement <= 0x100000000LL) && (displacement > (-0x100000000LL)) &&
344 "arm64 ADRP out of range");
345 assert(((instruction & 0x9F000000) == 0x90000000) &&
346 "reloc not on ADRP instruction");
347 uint32_t immhi = (displacement >> 9) & (0x00FFFFE0);
348 uint32_t immlo = (displacement << 17) & (0x60000000);
349 return (instruction & 0x9F00001F) | immlo | immhi;
350 }
351
352 ArchHandler_arm64::Arm64Kind
offset12KindFromInstruction(uint32_t instruction)353 ArchHandler_arm64::offset12KindFromInstruction(uint32_t instruction) {
354 if (instruction & 0x08000000) {
355 switch ((instruction >> 30) & 0x3) {
356 case 0:
357 if ((instruction & 0x04800000) == 0x04800000)
358 return offset12scale16;
359 return offset12;
360 case 1:
361 return offset12scale2;
362 case 2:
363 return offset12scale4;
364 case 3:
365 return offset12scale8;
366 }
367 }
368 return offset12;
369 }
370
setImm12(uint32_t instruction,uint32_t offset)371 uint32_t ArchHandler_arm64::setImm12(uint32_t instruction, uint32_t offset) {
372 assert(((offset & 0xFFFFF000) == 0) && "imm12 offset out of range");
373 uint32_t imm12 = offset << 10;
374 return (instruction & 0xFFC003FF) | imm12;
375 }
376
getReferenceInfo(const Relocation & reloc,const DefinedAtom * inAtom,uint32_t offsetInAtom,uint64_t fixupAddress,bool isBig,FindAtomBySectionAndAddress atomFromAddress,FindAtomBySymbolIndex atomFromSymbolIndex,Reference::KindValue * kind,const lld::Atom ** target,Reference::Addend * addend)377 llvm::Error ArchHandler_arm64::getReferenceInfo(
378 const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
379 uint64_t fixupAddress, bool isBig,
380 FindAtomBySectionAndAddress atomFromAddress,
381 FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
382 const lld::Atom **target, Reference::Addend *addend) {
383 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
384 switch (relocPattern(reloc)) {
385 case ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4:
386 // ex: bl _foo
387 *kind = branch26;
388 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
389 return ec;
390 *addend = 0;
391 return llvm::Error::success();
392 case ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4:
393 // ex: adrp x1, _foo@PAGE
394 *kind = page21;
395 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
396 return ec;
397 *addend = 0;
398 return llvm::Error::success();
399 case ARM64_RELOC_PAGEOFF12 | rExtern | rLength4:
400 // ex: ldr x0, [x1, _foo@PAGEOFF]
401 *kind = offset12KindFromInstruction(*(const little32_t *)fixupContent);
402 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
403 return ec;
404 *addend = 0;
405 return llvm::Error::success();
406 case ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
407 // ex: adrp x1, _foo@GOTPAGE
408 *kind = gotPage21;
409 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
410 return ec;
411 *addend = 0;
412 return llvm::Error::success();
413 case ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4:
414 // ex: ldr x0, [x1, _foo@GOTPAGEOFF]
415 *kind = gotOffset12;
416 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
417 return ec;
418 *addend = 0;
419 return llvm::Error::success();
420 case ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4:
421 // ex: adrp x1, _foo@TLVPAGE
422 *kind = tlvPage21;
423 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
424 return ec;
425 *addend = 0;
426 return llvm::Error::success();
427 case ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4:
428 // ex: ldr x0, [x1, _foo@TLVPAGEOFF]
429 *kind = tlvOffset12;
430 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
431 return ec;
432 *addend = 0;
433 return llvm::Error::success();
434 case ARM64_RELOC_UNSIGNED | rExtern | rLength8:
435 // ex: .quad _foo + N
436 *kind = pointer64;
437 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
438 return ec;
439 *addend = *(const little64_t *)fixupContent;
440 return llvm::Error::success();
441 case ARM64_RELOC_UNSIGNED | rLength8:
442 // ex: .quad Lfoo + N
443 *kind = pointer64;
444 return atomFromAddress(reloc.symbol, *(const little64_t *)fixupContent,
445 target, addend);
446 case ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8:
447 // ex: .quad _foo@GOT
448 *kind = pointer64ToGOT;
449 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
450 return ec;
451 *addend = 0;
452 return llvm::Error::success();
453 case ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4:
454 // ex: .long _foo@GOT - .
455
456 // If we are in an .eh_frame section, then the kind of the relocation should
457 // not be delta32ToGOT. It may instead be unwindCIEToPersonalityFunction.
458 if (inAtom->contentType() == DefinedAtom::typeCFI)
459 *kind = unwindCIEToPersonalityFunction;
460 else
461 *kind = delta32ToGOT;
462
463 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
464 return ec;
465 *addend = 0;
466 return llvm::Error::success();
467 default:
468 return llvm::make_error<GenericError>("unsupported arm64 relocation type");
469 }
470 }
471
getPairReferenceInfo(const normalized::Relocation & reloc1,const normalized::Relocation & reloc2,const DefinedAtom * inAtom,uint32_t offsetInAtom,uint64_t fixupAddress,bool swap,bool scatterable,FindAtomBySectionAndAddress atomFromAddress,FindAtomBySymbolIndex atomFromSymbolIndex,Reference::KindValue * kind,const lld::Atom ** target,Reference::Addend * addend)472 llvm::Error ArchHandler_arm64::getPairReferenceInfo(
473 const normalized::Relocation &reloc1, const normalized::Relocation &reloc2,
474 const DefinedAtom *inAtom, uint32_t offsetInAtom, uint64_t fixupAddress,
475 bool swap, bool scatterable, FindAtomBySectionAndAddress atomFromAddress,
476 FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
477 const lld::Atom **target, Reference::Addend *addend) {
478 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
479 switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
480 case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
481 ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4):
482 // ex: bl _foo+8
483 *kind = branch26;
484 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
485 return ec;
486 *addend = reloc1.symbol;
487 return llvm::Error::success();
488 case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
489 ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4):
490 // ex: adrp x1, _foo@PAGE
491 *kind = page21;
492 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
493 return ec;
494 *addend = reloc1.symbol;
495 return llvm::Error::success();
496 case ((ARM64_RELOC_ADDEND | rLength4) << 16 |
497 ARM64_RELOC_PAGEOFF12 | rExtern | rLength4): {
498 // ex: ldr w0, [x1, _foo@PAGEOFF]
499 uint32_t cont32 = (int32_t)*(const little32_t *)fixupContent;
500 *kind = offset12KindFromInstruction(cont32);
501 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
502 return ec;
503 *addend = reloc1.symbol;
504 return llvm::Error::success();
505 }
506 case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
507 ARM64_RELOC_UNSIGNED | rExtern | rLength8):
508 // ex: .quad _foo - .
509 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
510 return ec;
511
512 // If we are in an .eh_frame section, then the kind of the relocation should
513 // not be delta64. It may instead be unwindFDEToFunction.
514 if (inAtom->contentType() == DefinedAtom::typeCFI)
515 *kind = unwindFDEToFunction;
516 else
517 *kind = delta64;
518
519 // The offsets of the 2 relocations must match
520 if (reloc1.offset != reloc2.offset)
521 return llvm::make_error<GenericError>(
522 "paired relocs must have the same offset");
523 *addend = (int64_t)*(const little64_t *)fixupContent + offsetInAtom;
524 return llvm::Error::success();
525 case ((ARM64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
526 ARM64_RELOC_UNSIGNED | rExtern | rLength4):
527 // ex: .quad _foo - .
528 *kind = delta32;
529 if (auto ec = atomFromSymbolIndex(reloc2.symbol, target))
530 return ec;
531 *addend = (int32_t)*(const little32_t *)fixupContent + offsetInAtom;
532 return llvm::Error::success();
533 default:
534 return llvm::make_error<GenericError>("unsupported arm64 relocation pair");
535 }
536 }
537
generateAtomContent(const DefinedAtom & atom,bool relocatable,FindAddressForAtom findAddress,FindAddressForAtom findSectionAddress,uint64_t imageBaseAddress,llvm::MutableArrayRef<uint8_t> atomContentBuffer)538 void ArchHandler_arm64::generateAtomContent(
539 const DefinedAtom &atom, bool relocatable, FindAddressForAtom findAddress,
540 FindAddressForAtom findSectionAddress, uint64_t imageBaseAddress,
541 llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
542 // Copy raw bytes.
543 std::copy(atom.rawContent().begin(), atom.rawContent().end(),
544 atomContentBuffer.begin());
545 // Apply fix-ups.
546 #ifndef NDEBUG
547 if (atom.begin() != atom.end()) {
548 DEBUG_WITH_TYPE("atom-content", llvm::dbgs()
549 << "Applying fixups to atom:\n"
550 << " address="
551 << llvm::format(" 0x%09lX", &atom)
552 << ", file=#"
553 << atom.file().ordinal()
554 << ", atom=#"
555 << atom.ordinal()
556 << ", name="
557 << atom.name()
558 << ", type="
559 << atom.contentType()
560 << "\n");
561 }
562 #endif
563 for (const Reference *ref : atom) {
564 uint32_t offset = ref->offsetInAtom();
565 const Atom *target = ref->target();
566 bool targetUnnamed = target->name().empty();
567 uint64_t targetAddress = 0;
568 if (isa<DefinedAtom>(target))
569 targetAddress = findAddress(*target);
570 uint64_t atomAddress = findAddress(atom);
571 uint64_t fixupAddress = atomAddress + offset;
572 if (relocatable) {
573 applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
574 targetAddress, atomAddress, targetUnnamed);
575 } else {
576 applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
577 targetAddress, atomAddress, imageBaseAddress,
578 findSectionAddress);
579 }
580 }
581 }
582
applyFixupFinal(const Reference & ref,uint8_t * loc,uint64_t fixupAddress,uint64_t targetAddress,uint64_t inAtomAddress,uint64_t imageBaseAddress,FindAddressForAtom findSectionAddress)583 void ArchHandler_arm64::applyFixupFinal(const Reference &ref, uint8_t *loc,
584 uint64_t fixupAddress,
585 uint64_t targetAddress,
586 uint64_t inAtomAddress,
587 uint64_t imageBaseAddress,
588 FindAddressForAtom findSectionAddress) {
589 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
590 return;
591 assert(ref.kindArch() == Reference::KindArch::AArch64);
592 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
593 ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
594 int32_t displacement;
595 uint32_t instruction;
596 uint32_t value32;
597 uint32_t value64;
598 switch (static_cast<Arm64Kind>(ref.kindValue())) {
599 case branch26:
600 displacement = (targetAddress - fixupAddress) + ref.addend();
601 *loc32 = setDisplacementInBranch26(*loc32, displacement);
602 return;
603 case page21:
604 case gotPage21:
605 case tlvPage21:
606 displacement =
607 ((targetAddress + ref.addend()) & (-4096)) - (fixupAddress & (-4096));
608 *loc32 = setDisplacementInADRP(*loc32, displacement);
609 return;
610 case offset12:
611 case gotOffset12:
612 case tlvOffset12:
613 displacement = (targetAddress + ref.addend()) & 0x00000FFF;
614 *loc32 = setImm12(*loc32, displacement);
615 return;
616 case offset12scale2:
617 displacement = (targetAddress + ref.addend()) & 0x00000FFF;
618 assert(((displacement & 0x1) == 0) &&
619 "scaled imm12 not accessing 2-byte aligneds");
620 *loc32 = setImm12(*loc32, displacement >> 1);
621 return;
622 case offset12scale4:
623 displacement = (targetAddress + ref.addend()) & 0x00000FFF;
624 assert(((displacement & 0x3) == 0) &&
625 "scaled imm12 not accessing 4-byte aligned");
626 *loc32 = setImm12(*loc32, displacement >> 2);
627 return;
628 case offset12scale8:
629 displacement = (targetAddress + ref.addend()) & 0x00000FFF;
630 assert(((displacement & 0x7) == 0) &&
631 "scaled imm12 not accessing 8-byte aligned");
632 *loc32 = setImm12(*loc32, displacement >> 3);
633 return;
634 case offset12scale16:
635 displacement = (targetAddress + ref.addend()) & 0x00000FFF;
636 assert(((displacement & 0xF) == 0) &&
637 "scaled imm12 not accessing 16-byte aligned");
638 *loc32 = setImm12(*loc32, displacement >> 4);
639 return;
640 case addOffset12:
641 instruction = *loc32;
642 assert(((instruction & 0xFFC00000) == 0xF9400000) &&
643 "GOT reloc is not an LDR instruction");
644 displacement = (targetAddress + ref.addend()) & 0x00000FFF;
645 value32 = 0x91000000 | (instruction & 0x000003FF);
646 instruction = setImm12(value32, displacement);
647 *loc32 = instruction;
648 return;
649 case pointer64:
650 case pointer64ToGOT:
651 *loc64 = targetAddress + ref.addend();
652 return;
653 case delta64:
654 case unwindFDEToFunction:
655 *loc64 = (targetAddress - fixupAddress) + ref.addend();
656 return;
657 case delta32:
658 case delta32ToGOT:
659 case unwindCIEToPersonalityFunction:
660 *loc32 = (targetAddress - fixupAddress) + ref.addend();
661 return;
662 case negDelta32:
663 *loc32 = fixupAddress - targetAddress + ref.addend();
664 return;
665 case lazyPointer:
666 // Do nothing
667 return;
668 case lazyImmediateLocation:
669 *loc32 = ref.addend();
670 return;
671 case imageOffset:
672 *loc32 = (targetAddress - imageBaseAddress) + ref.addend();
673 return;
674 case imageOffsetGot:
675 llvm_unreachable("imageOffsetGot should have been changed to imageOffset");
676 break;
677 case unwindInfoToEhFrame:
678 value64 = targetAddress - findSectionAddress(*ref.target()) + ref.addend();
679 assert(value64 < 0xffffffU && "offset in __eh_frame too large");
680 *loc32 = (*loc32 & 0xff000000U) | value64;
681 return;
682 case invalid:
683 // Fall into llvm_unreachable().
684 break;
685 }
686 llvm_unreachable("invalid arm64 Reference Kind");
687 }
688
applyFixupRelocatable(const Reference & ref,uint8_t * loc,uint64_t fixupAddress,uint64_t targetAddress,uint64_t inAtomAddress,bool targetUnnamed)689 void ArchHandler_arm64::applyFixupRelocatable(const Reference &ref,
690 uint8_t *loc,
691 uint64_t fixupAddress,
692 uint64_t targetAddress,
693 uint64_t inAtomAddress,
694 bool targetUnnamed) {
695 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
696 return;
697 assert(ref.kindArch() == Reference::KindArch::AArch64);
698 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
699 ulittle64_t *loc64 = reinterpret_cast<ulittle64_t *>(loc);
700 switch (static_cast<Arm64Kind>(ref.kindValue())) {
701 case branch26:
702 *loc32 = setDisplacementInBranch26(*loc32, 0);
703 return;
704 case page21:
705 case gotPage21:
706 case tlvPage21:
707 *loc32 = setDisplacementInADRP(*loc32, 0);
708 return;
709 case offset12:
710 case offset12scale2:
711 case offset12scale4:
712 case offset12scale8:
713 case offset12scale16:
714 case gotOffset12:
715 case tlvOffset12:
716 *loc32 = setImm12(*loc32, 0);
717 return;
718 case pointer64:
719 if (targetUnnamed)
720 *loc64 = targetAddress + ref.addend();
721 else
722 *loc64 = ref.addend();
723 return;
724 case delta64:
725 *loc64 = ref.addend() + inAtomAddress - fixupAddress;
726 return;
727 case unwindFDEToFunction:
728 // We don't emit unwindFDEToFunction in -r mode as they are implicitly
729 // generated from the data in the __eh_frame section. So here we need
730 // to use the targetAddress so that we can generate the full relocation
731 // when we parse again later.
732 *loc64 = targetAddress - fixupAddress;
733 return;
734 case delta32:
735 *loc32 = ref.addend() + inAtomAddress - fixupAddress;
736 return;
737 case negDelta32:
738 // We don't emit negDelta32 in -r mode as they are implicitly
739 // generated from the data in the __eh_frame section. So here we need
740 // to use the targetAddress so that we can generate the full relocation
741 // when we parse again later.
742 *loc32 = fixupAddress - targetAddress + ref.addend();
743 return;
744 case pointer64ToGOT:
745 *loc64 = 0;
746 return;
747 case delta32ToGOT:
748 *loc32 = inAtomAddress - fixupAddress;
749 return;
750 case unwindCIEToPersonalityFunction:
751 // We don't emit unwindCIEToPersonalityFunction in -r mode as they are
752 // implicitly generated from the data in the __eh_frame section. So here we
753 // need to use the targetAddress so that we can generate the full relocation
754 // when we parse again later.
755 *loc32 = targetAddress - fixupAddress;
756 return;
757 case addOffset12:
758 llvm_unreachable("lazy reference kind implies GOT pass was run");
759 case lazyPointer:
760 case lazyImmediateLocation:
761 llvm_unreachable("lazy reference kind implies Stubs pass was run");
762 case imageOffset:
763 case imageOffsetGot:
764 case unwindInfoToEhFrame:
765 llvm_unreachable("fixup implies __unwind_info");
766 return;
767 case invalid:
768 // Fall into llvm_unreachable().
769 break;
770 }
771 llvm_unreachable("unknown arm64 Reference Kind");
772 }
773
appendSectionRelocations(const DefinedAtom & atom,uint64_t atomSectionOffset,const Reference & ref,FindSymbolIndexForAtom symbolIndexForAtom,FindSectionIndexForAtom sectionIndexForAtom,FindAddressForAtom addressForAtom,normalized::Relocations & relocs)774 void ArchHandler_arm64::appendSectionRelocations(
775 const DefinedAtom &atom, uint64_t atomSectionOffset, const Reference &ref,
776 FindSymbolIndexForAtom symbolIndexForAtom,
777 FindSectionIndexForAtom sectionIndexForAtom,
778 FindAddressForAtom addressForAtom, normalized::Relocations &relocs) {
779 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
780 return;
781 assert(ref.kindArch() == Reference::KindArch::AArch64);
782 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
783 switch (static_cast<Arm64Kind>(ref.kindValue())) {
784 case branch26:
785 if (ref.addend()) {
786 appendReloc(relocs, sectionOffset, ref.addend(), 0,
787 ARM64_RELOC_ADDEND | rLength4);
788 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
789 ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
790 } else {
791 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
792 ARM64_RELOC_BRANCH26 | rPcRel | rExtern | rLength4);
793 }
794 return;
795 case page21:
796 if (ref.addend()) {
797 appendReloc(relocs, sectionOffset, ref.addend(), 0,
798 ARM64_RELOC_ADDEND | rLength4);
799 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
800 ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
801 } else {
802 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
803 ARM64_RELOC_PAGE21 | rPcRel | rExtern | rLength4);
804 }
805 return;
806 case offset12:
807 case offset12scale2:
808 case offset12scale4:
809 case offset12scale8:
810 case offset12scale16:
811 if (ref.addend()) {
812 appendReloc(relocs, sectionOffset, ref.addend(), 0,
813 ARM64_RELOC_ADDEND | rLength4);
814 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
815 ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
816 } else {
817 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
818 ARM64_RELOC_PAGEOFF12 | rExtern | rLength4);
819 }
820 return;
821 case gotPage21:
822 assert(ref.addend() == 0);
823 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
824 ARM64_RELOC_GOT_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
825 return;
826 case gotOffset12:
827 assert(ref.addend() == 0);
828 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
829 ARM64_RELOC_GOT_LOAD_PAGEOFF12 | rExtern | rLength4);
830 return;
831 case tlvPage21:
832 assert(ref.addend() == 0);
833 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
834 ARM64_RELOC_TLVP_LOAD_PAGE21 | rPcRel | rExtern | rLength4);
835 return;
836 case tlvOffset12:
837 assert(ref.addend() == 0);
838 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
839 ARM64_RELOC_TLVP_LOAD_PAGEOFF12 | rExtern | rLength4);
840 return;
841 case pointer64:
842 if (ref.target()->name().empty())
843 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
844 ARM64_RELOC_UNSIGNED | rLength8);
845 else
846 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
847 ARM64_RELOC_UNSIGNED | rExtern | rLength8);
848 return;
849 case delta64:
850 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
851 ARM64_RELOC_SUBTRACTOR | rExtern | rLength8);
852 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
853 ARM64_RELOC_UNSIGNED | rExtern | rLength8);
854 return;
855 case delta32:
856 appendReloc(relocs, sectionOffset, symbolIndexForAtom(atom), 0,
857 ARM64_RELOC_SUBTRACTOR | rExtern | rLength4 );
858 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
859 ARM64_RELOC_UNSIGNED | rExtern | rLength4 );
860 return;
861 case pointer64ToGOT:
862 assert(ref.addend() == 0);
863 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
864 ARM64_RELOC_POINTER_TO_GOT | rExtern | rLength8);
865 return;
866 case delta32ToGOT:
867 assert(ref.addend() == 0);
868 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
869 ARM64_RELOC_POINTER_TO_GOT | rPcRel | rExtern | rLength4);
870 return;
871 case addOffset12:
872 llvm_unreachable("lazy reference kind implies GOT pass was run");
873 case lazyPointer:
874 case lazyImmediateLocation:
875 llvm_unreachable("lazy reference kind implies Stubs pass was run");
876 case imageOffset:
877 case imageOffsetGot:
878 llvm_unreachable("deltas from mach_header can only be in final images");
879 case unwindCIEToPersonalityFunction:
880 case unwindFDEToFunction:
881 case unwindInfoToEhFrame:
882 case negDelta32:
883 // Do nothing.
884 return;
885 case invalid:
886 // Fall into llvm_unreachable().
887 break;
888 }
889 llvm_unreachable("unknown arm64 Reference Kind");
890 }
891
create_arm64()892 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm64() {
893 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm64());
894 }
895
896 } // namespace mach_o
897 } // namespace lld
898