1 //===- lib/FileFormat/MachO/ArchHandler_arm.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
18 using namespace llvm::MachO;
19 using namespace lld::mach_o::normalized;
20
21 namespace lld {
22 namespace mach_o {
23
24 using llvm::support::ulittle32_t;
25 using llvm::support::little32_t;
26
27
28 class ArchHandler_arm : public ArchHandler {
29 public:
30 ArchHandler_arm() = default;
31 ~ArchHandler_arm() override = default;
32
kindStrings()33 const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
34
kindArch()35 Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
36
37 const ArchHandler::StubInfo &stubInfo() override;
38 bool isCallSite(const Reference &) override;
39 bool isPointer(const Reference &) override;
40 bool isPairedReloc(const normalized::Relocation &) override;
41 bool isNonCallBranch(const Reference &) override;
42
needsCompactUnwind()43 bool needsCompactUnwind() override {
44 return false;
45 }
imageOffsetKind()46 Reference::KindValue imageOffsetKind() override {
47 return invalid;
48 }
imageOffsetKindIndirect()49 Reference::KindValue imageOffsetKindIndirect() override {
50 return invalid;
51 }
52
unwindRefToPersonalityFunctionKind()53 Reference::KindValue unwindRefToPersonalityFunctionKind() override {
54 return invalid;
55 }
56
unwindRefToCIEKind()57 Reference::KindValue unwindRefToCIEKind() override {
58 return invalid;
59 }
60
unwindRefToFunctionKind()61 Reference::KindValue unwindRefToFunctionKind() override {
62 return invalid;
63 }
64
unwindRefToEhFrameKind()65 Reference::KindValue unwindRefToEhFrameKind() override {
66 return invalid;
67 }
68
lazyImmediateLocationKind()69 Reference::KindValue lazyImmediateLocationKind() override {
70 return lazyImmediateLocation;
71 }
72
pointerKind()73 Reference::KindValue pointerKind() override {
74 return invalid;
75 }
76
dwarfCompactUnwindType()77 uint32_t dwarfCompactUnwindType() override {
78 // FIXME
79 return -1;
80 }
81
82 llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
83 const DefinedAtom *inAtom,
84 uint32_t offsetInAtom,
85 uint64_t fixupAddress, bool swap,
86 FindAtomBySectionAndAddress atomFromAddress,
87 FindAtomBySymbolIndex atomFromSymbolIndex,
88 Reference::KindValue *kind,
89 const lld::Atom **target,
90 Reference::Addend *addend) override;
91 llvm::Error
92 getPairReferenceInfo(const normalized::Relocation &reloc1,
93 const normalized::Relocation &reloc2,
94 const DefinedAtom *inAtom,
95 uint32_t offsetInAtom,
96 uint64_t fixupAddress, bool swap, bool scatterable,
97 FindAtomBySectionAndAddress atomFromAddress,
98 FindAtomBySymbolIndex atomFromSymbolIndex,
99 Reference::KindValue *kind,
100 const lld::Atom **target,
101 Reference::Addend *addend) override;
102
103 void generateAtomContent(const DefinedAtom &atom, bool relocatable,
104 FindAddressForAtom findAddress,
105 FindAddressForAtom findSectionAddress,
106 uint64_t imageBaseAddress,
107 llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
108
109 void appendSectionRelocations(const DefinedAtom &atom,
110 uint64_t atomSectionOffset,
111 const Reference &ref,
112 FindSymbolIndexForAtom,
113 FindSectionIndexForAtom,
114 FindAddressForAtom,
115 normalized::Relocations &) override;
116
117 void addAdditionalReferences(MachODefinedAtom &atom) override;
118
isDataInCodeTransition(Reference::KindValue refKind)119 bool isDataInCodeTransition(Reference::KindValue refKind) override {
120 switch (refKind) {
121 case modeThumbCode:
122 case modeArmCode:
123 case modeData:
124 return true;
125 default:
126 return false;
127 break;
128 }
129 }
130
dataInCodeTransitionStart(const MachODefinedAtom & atom)131 Reference::KindValue dataInCodeTransitionStart(
132 const MachODefinedAtom &atom) override {
133 return modeData;
134 }
135
dataInCodeTransitionEnd(const MachODefinedAtom & atom)136 Reference::KindValue dataInCodeTransitionEnd(
137 const MachODefinedAtom &atom) override {
138 return atom.isThumb() ? modeThumbCode : modeArmCode;
139 }
140
141 bool isThumbFunction(const DefinedAtom &atom) override;
142 const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
143 const DefinedAtom &) override;
144
145 private:
146 friend class Thumb2ToArmShimAtom;
147 friend class ArmToThumbShimAtom;
148
149 static const Registry::KindStrings _sKindStrings[];
150 static const StubInfo _sStubInfoArmPIC;
151
152 enum ArmKind : Reference::KindValue {
153 invalid, /// for error condition
154
155 modeThumbCode, /// Content starting at this offset is thumb.
156 modeArmCode, /// Content starting at this offset is arm.
157 modeData, /// Content starting at this offset is data.
158
159 // Kinds found in mach-o .o files:
160 thumb_bl22, /// ex: bl _foo
161 thumb_b22, /// ex: b _foo
162 thumb_movw, /// ex: movw r1, :lower16:_foo
163 thumb_movt, /// ex: movt r1, :lower16:_foo
164 thumb_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
165 thumb_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
166 arm_bl24, /// ex: bl _foo
167 arm_b24, /// ex: b _foo
168 arm_movw, /// ex: movw r1, :lower16:_foo
169 arm_movt, /// ex: movt r1, :lower16:_foo
170 arm_movw_funcRel, /// ex: movw r1, :lower16:(_foo-(L1+4))
171 arm_movt_funcRel, /// ex: movt r1, :upper16:(_foo-(L1+4))
172 pointer32, /// ex: .long _foo
173 delta32, /// ex: .long _foo - .
174
175 // Kinds introduced by Passes:
176 lazyPointer, /// Location contains a lazy pointer.
177 lazyImmediateLocation, /// Location contains immediate value used in stub.
178 };
179
180 // Utility functions for inspecting/updating instructions.
181 static bool isThumbMovw(uint32_t instruction);
182 static bool isThumbMovt(uint32_t instruction);
183 static bool isArmMovw(uint32_t instruction);
184 static bool isArmMovt(uint32_t instruction);
185 static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t);
186 static int32_t getDisplacementFromArmBranch(uint32_t instruction);
187 static uint16_t getWordFromThumbMov(uint32_t instruction);
188 static uint16_t getWordFromArmMov(uint32_t instruction);
189 static uint32_t clearThumbBit(uint32_t value, const Atom *target);
190 static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp,
191 bool targetIsThumb);
192 static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia,
193 int32_t disp, bool targetThumb);
194 static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
195 static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
196
197 StringRef stubName(const DefinedAtom &);
198 bool useExternalRelocationTo(const Atom &target);
199
200 void applyFixupFinal(const Reference &ref, uint8_t *location,
201 uint64_t fixupAddress, uint64_t targetAddress,
202 uint64_t inAtomAddress, bool &thumbMode,
203 bool targetIsThumb);
204
205 void applyFixupRelocatable(const Reference &ref, uint8_t *location,
206 uint64_t fixupAddress,
207 uint64_t targetAddress,
208 uint64_t inAtomAddress, bool &thumbMode,
209 bool targetIsThumb);
210 };
211
212 //===----------------------------------------------------------------------===//
213 // ArchHandler_arm
214 //===----------------------------------------------------------------------===//
215
216 const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
217 LLD_KIND_STRING_ENTRY(invalid),
218 LLD_KIND_STRING_ENTRY(modeThumbCode),
219 LLD_KIND_STRING_ENTRY(modeArmCode),
220 LLD_KIND_STRING_ENTRY(modeData),
221 LLD_KIND_STRING_ENTRY(thumb_bl22),
222 LLD_KIND_STRING_ENTRY(thumb_b22),
223 LLD_KIND_STRING_ENTRY(thumb_movw),
224 LLD_KIND_STRING_ENTRY(thumb_movt),
225 LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
226 LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
227 LLD_KIND_STRING_ENTRY(arm_bl24),
228 LLD_KIND_STRING_ENTRY(arm_b24),
229 LLD_KIND_STRING_ENTRY(arm_movw),
230 LLD_KIND_STRING_ENTRY(arm_movt),
231 LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
232 LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
233 LLD_KIND_STRING_ENTRY(pointer32),
234 LLD_KIND_STRING_ENTRY(delta32),
235 LLD_KIND_STRING_ENTRY(lazyPointer),
236 LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
237 LLD_KIND_STRING_END
238 };
239
240 const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
241 "dyld_stub_binder",
242
243 // References in lazy pointer
244 { Reference::KindArch::ARM, pointer32, 0, 0 },
245 { Reference::KindArch::ARM, lazyPointer, 0, 0 },
246
247 // GOT pointer to dyld_stub_binder
248 { Reference::KindArch::ARM, pointer32, 0, 0 },
249
250 // arm code alignment 2^2
251 2,
252
253 // Stub size and code
254 16,
255 { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 12
256 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
257 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
258 0x00, 0x00, 0x00, 0x00 }, // .long L_foo$lazy_ptr - (L1$scv + 8)
259 { Reference::KindArch::ARM, delta32, 12, 0 },
260 { false, 0, 0, 0 },
261
262 // Stub Helper size and code
263 12,
264 { 0x00, 0xC0, 0x9F, 0xE5, // ldr ip, [pc, #0]
265 0x00, 0x00, 0x00, 0xEA, // b _helperhelper
266 0x00, 0x00, 0x00, 0x00 }, // .long lazy-info-offset
267 { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
268 { Reference::KindArch::ARM, arm_b24, 4, 0 },
269
270 // Stub helper image cache content type
271 DefinedAtom::typeGOT,
272
273 // Stub Helper-Common size and code
274 36,
275 // Stub helper alignment
276 2,
277 { // push lazy-info-offset
278 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
279 // push address of dyld_mageLoaderCache
280 0x10, 0xC0, 0x9F, 0xE5, // ldr ip, L1
281 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
282 0x04, 0xC0, 0x2D, 0xE5, // str ip, [sp, #-4]!
283 // jump through dyld_stub_binder
284 0x08, 0xC0, 0x9F, 0xE5, // ldr ip, L2
285 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
286 0x00, 0xF0, 0x9C, 0xE5, // ldr pc, [ip]
287 0x00, 0x00, 0x00, 0x00, // L1: .long fFastStubGOTAtom - (helper+16)
288 0x00, 0x00, 0x00, 0x00 }, // L2: .long dyld_stub_binder - (helper+28)
289 { Reference::KindArch::ARM, delta32, 28, 0xC },
290 { false, 0, 0, 0 },
291 { Reference::KindArch::ARM, delta32, 32, 0x04 },
292 { false, 0, 0, 0 }
293 };
294
stubInfo()295 const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
296 // If multiple kinds of stubs are supported, select which StubInfo here.
297 return _sStubInfoArmPIC;
298 }
299
isCallSite(const Reference & ref)300 bool ArchHandler_arm::isCallSite(const Reference &ref) {
301 switch (ref.kindValue()) {
302 case thumb_b22:
303 case thumb_bl22:
304 case arm_b24:
305 case arm_bl24:
306 return true;
307 default:
308 return false;
309 }
310 }
311
isPointer(const Reference & ref)312 bool ArchHandler_arm::isPointer(const Reference &ref) {
313 return (ref.kindValue() == pointer32);
314 }
315
isNonCallBranch(const Reference & ref)316 bool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
317 switch (ref.kindValue()) {
318 case thumb_b22:
319 case arm_b24:
320 return true;
321 default:
322 return false;
323 }
324 }
325
isPairedReloc(const Relocation & reloc)326 bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
327 switch (reloc.type) {
328 case ARM_RELOC_SECTDIFF:
329 case ARM_RELOC_LOCAL_SECTDIFF:
330 case ARM_RELOC_HALF_SECTDIFF:
331 case ARM_RELOC_HALF:
332 return true;
333 default:
334 return false;
335 }
336 }
337
338 /// Trace references from stub atom to lazy pointer to target and get its name.
stubName(const DefinedAtom & stubAtom)339 StringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
340 assert(stubAtom.contentType() == DefinedAtom::typeStub);
341 for (const Reference *ref : stubAtom) {
342 if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
343 if (lp->contentType() != DefinedAtom::typeLazyPointer)
344 continue;
345 for (const Reference *ref2 : *lp) {
346 if (ref2->kindValue() != lazyPointer)
347 continue;
348 return ref2->target()->name();
349 }
350 }
351 }
352 return "stub";
353 }
354
355 /// Extract displacement from an ARM b/bl/blx instruction.
getDisplacementFromArmBranch(uint32_t instruction)356 int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
357 // Sign-extend imm24
358 int32_t displacement = (instruction & 0x00FFFFFF) << 2;
359 if ((displacement & 0x02000000) != 0)
360 displacement |= 0xFC000000;
361 // If this is BLX and H bit set, add 2.
362 if ((instruction & 0xFF000000) == 0xFB000000)
363 displacement += 2;
364 return displacement;
365 }
366
367 /// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed.
setDisplacementInArmBranch(uint32_t instruction,int32_t displacement,bool targetIsThumb)368 uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
369 int32_t displacement,
370 bool targetIsThumb) {
371 assert((displacement <= 33554428) && (displacement > (-33554432))
372 && "arm branch out of range");
373 bool is_blx = ((instruction & 0xF0000000) == 0xF0000000);
374 uint32_t newInstruction = (instruction & 0xFF000000);
375 uint32_t h = 0;
376 if (targetIsThumb) {
377 // Force use of BLX.
378 newInstruction = 0xFA000000;
379 if (!is_blx) {
380 assert(((instruction & 0xF0000000) == 0xE0000000)
381 && "no conditional arm blx");
382 assert(((instruction & 0xFF000000) == 0xEB000000)
383 && "no arm pc-rel BX instruction");
384 }
385 if (displacement & 2)
386 h = 1;
387 }
388 else {
389 // Force use of B/BL.
390 if (is_blx)
391 newInstruction = 0xEB000000;
392 }
393 newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF);
394 return newInstruction;
395 }
396
397 /// Extract displacement from a thumb b/bl/blx instruction.
getDisplacementFromThumbBranch(uint32_t instruction,uint32_t instrAddr)398 int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction,
399 uint32_t instrAddr) {
400 bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
401 uint32_t s = (instruction >> 10) & 0x1;
402 uint32_t j1 = (instruction >> 29) & 0x1;
403 uint32_t j2 = (instruction >> 27) & 0x1;
404 uint32_t imm10 = instruction & 0x3FF;
405 uint32_t imm11 = (instruction >> 16) & 0x7FF;
406 uint32_t i1 = (j1 == s);
407 uint32_t i2 = (j2 == s);
408 uint32_t dis =
409 (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
410 int32_t sdis = dis;
411 int32_t result = s ? (sdis | 0xFE000000) : sdis;
412 if (is_blx && (instrAddr & 0x2)) {
413 // The thumb blx instruction always has low bit of imm11 as zero. The way
414 // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that
415 // the blx instruction always 4-byte aligns the pc before adding the
416 // displacement from the blx. We must emulate that when decoding this.
417 result -= 2;
418 }
419 return result;
420 }
421
422 /// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed.
setDisplacementInThumbBranch(uint32_t instruction,uint32_t instrAddr,int32_t displacement,bool targetIsThumb)423 uint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
424 uint32_t instrAddr,
425 int32_t displacement,
426 bool targetIsThumb) {
427 assert((displacement <= 16777214) && (displacement > (-16777216))
428 && "thumb branch out of range");
429 bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
430 bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
431 bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
432 uint32_t newInstruction = (instruction & 0xD000F800);
433 if (is_bl || is_blx) {
434 if (targetIsThumb) {
435 newInstruction = 0xD000F000; // Use bl
436 } else {
437 newInstruction = 0xC000F000; // Use blx
438 // See note in getDisplacementFromThumbBranch() about blx.
439 if (instrAddr & 0x2)
440 displacement += 2;
441 }
442 } else if (is_b) {
443 assert(targetIsThumb && "no pc-rel thumb branch instruction that "
444 "switches to arm mode");
445 }
446 else {
447 llvm_unreachable("thumb branch22 reloc on a non-branch instruction");
448 }
449 uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
450 uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
451 uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
452 uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
453 uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
454 uint32_t j1 = (i1 == s);
455 uint32_t j2 = (i2 == s);
456 uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
457 uint32_t firstDisp = (s << 10) | imm10;
458 newInstruction |= (nextDisp << 16) | firstDisp;
459 return newInstruction;
460 }
461
isThumbMovw(uint32_t instruction)462 bool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
463 return (instruction & 0x8000FBF0) == 0x0000F240;
464 }
465
isThumbMovt(uint32_t instruction)466 bool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
467 return (instruction & 0x8000FBF0) == 0x0000F2C0;
468 }
469
isArmMovw(uint32_t instruction)470 bool ArchHandler_arm::isArmMovw(uint32_t instruction) {
471 return (instruction & 0x0FF00000) == 0x03000000;
472 }
473
isArmMovt(uint32_t instruction)474 bool ArchHandler_arm::isArmMovt(uint32_t instruction) {
475 return (instruction & 0x0FF00000) == 0x03400000;
476 }
477
getWordFromThumbMov(uint32_t instruction)478 uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
479 assert(isThumbMovw(instruction) || isThumbMovt(instruction));
480 uint32_t i = ((instruction & 0x00000400) >> 10);
481 uint32_t imm4 = (instruction & 0x0000000F);
482 uint32_t imm3 = ((instruction & 0x70000000) >> 28);
483 uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
484 return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
485 }
486
getWordFromArmMov(uint32_t instruction)487 uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
488 assert(isArmMovw(instruction) || isArmMovt(instruction));
489 uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
490 uint32_t imm12 = (instruction & 0x00000FFF);
491 return (imm4 << 12) | imm12;
492 }
493
setWordFromThumbMov(uint32_t instr,uint16_t word)494 uint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
495 assert(isThumbMovw(instr) || isThumbMovt(instr));
496 uint32_t imm4 = (word & 0xF000) >> 12;
497 uint32_t i = (word & 0x0800) >> 11;
498 uint32_t imm3 = (word & 0x0700) >> 8;
499 uint32_t imm8 = word & 0x00FF;
500 return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
501 }
502
setWordFromArmMov(uint32_t instr,uint16_t word)503 uint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
504 assert(isArmMovw(instr) || isArmMovt(instr));
505 uint32_t imm4 = (word & 0xF000) >> 12;
506 uint32_t imm12 = word & 0x0FFF;
507 return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
508 }
509
clearThumbBit(uint32_t value,const Atom * target)510 uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
511 // The assembler often adds one to the address of a thumb function.
512 // We need to undo that so it does not look like an addend.
513 if (value & 1) {
514 if (isa<DefinedAtom>(target)) {
515 const MachODefinedAtom *machoTarget =
516 reinterpret_cast<const MachODefinedAtom *>(target);
517 if (machoTarget->isThumb())
518 value &= -2; // mask off thumb-bit
519 }
520 }
521 return value;
522 }
523
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)524 llvm::Error ArchHandler_arm::getReferenceInfo(
525 const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
526 uint64_t fixupAddress, bool isBig,
527 FindAtomBySectionAndAddress atomFromAddress,
528 FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
529 const lld::Atom **target, Reference::Addend *addend) {
530 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
531 uint64_t targetAddress;
532 uint32_t instruction = *(const ulittle32_t *)fixupContent;
533 int32_t displacement;
534 switch (relocPattern(reloc)) {
535 case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
536 // ex: bl _foo (and _foo is undefined)
537 if ((instruction & 0xD000F800) == 0x9000F000)
538 *kind = thumb_b22;
539 else
540 *kind = thumb_bl22;
541 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
542 return ec;
543 // Instruction contains branch to addend.
544 displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
545 *addend = fixupAddress + 4 + displacement;
546 return llvm::Error::success();
547 case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
548 // ex: bl _foo (and _foo is defined)
549 if ((instruction & 0xD000F800) == 0x9000F000)
550 *kind = thumb_b22;
551 else
552 *kind = thumb_bl22;
553 displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
554 targetAddress = fixupAddress + 4 + displacement;
555 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
556 case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
557 // ex: bl _foo+4 (and _foo is defined)
558 if ((instruction & 0xD000F800) == 0x9000F000)
559 *kind = thumb_b22;
560 else
561 *kind = thumb_bl22;
562 displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
563 targetAddress = fixupAddress + 4 + displacement;
564 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
565 return ec;
566 // reloc.value is target atom's address. Instruction contains branch
567 // to atom+addend.
568 *addend += (targetAddress - reloc.value);
569 return llvm::Error::success();
570 case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
571 // ex: bl _foo (and _foo is undefined)
572 if (((instruction & 0x0F000000) == 0x0A000000)
573 && ((instruction & 0xF0000000) != 0xF0000000))
574 *kind = arm_b24;
575 else
576 *kind = arm_bl24;
577 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
578 return ec;
579 // Instruction contains branch to addend.
580 displacement = getDisplacementFromArmBranch(instruction);
581 *addend = fixupAddress + 8 + displacement;
582 return llvm::Error::success();
583 case ARM_RELOC_BR24 | rPcRel | rLength4:
584 // ex: bl _foo (and _foo is defined)
585 if (((instruction & 0x0F000000) == 0x0A000000)
586 && ((instruction & 0xF0000000) != 0xF0000000))
587 *kind = arm_b24;
588 else
589 *kind = arm_bl24;
590 displacement = getDisplacementFromArmBranch(instruction);
591 targetAddress = fixupAddress + 8 + displacement;
592 return atomFromAddress(reloc.symbol, targetAddress, target, addend);
593 case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
594 // ex: bl _foo+4 (and _foo is defined)
595 if (((instruction & 0x0F000000) == 0x0A000000)
596 && ((instruction & 0xF0000000) != 0xF0000000))
597 *kind = arm_b24;
598 else
599 *kind = arm_bl24;
600 displacement = getDisplacementFromArmBranch(instruction);
601 targetAddress = fixupAddress + 8 + displacement;
602 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
603 return ec;
604 // reloc.value is target atom's address. Instruction contains branch
605 // to atom+addend.
606 *addend += (targetAddress - reloc.value);
607 return llvm::Error::success();
608 case ARM_RELOC_VANILLA | rExtern | rLength4:
609 // ex: .long _foo (and _foo is undefined)
610 *kind = pointer32;
611 if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
612 return ec;
613 *addend = instruction;
614 return llvm::Error::success();
615 case ARM_RELOC_VANILLA | rLength4:
616 // ex: .long _foo (and _foo is defined)
617 *kind = pointer32;
618 if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
619 return ec;
620 *addend = clearThumbBit((uint32_t) * addend, *target);
621 return llvm::Error::success();
622 case ARM_RELOC_VANILLA | rScattered | rLength4:
623 // ex: .long _foo+a (and _foo is defined)
624 *kind = pointer32;
625 if (auto ec = atomFromAddress(0, reloc.value, target, addend))
626 return ec;
627 *addend += (clearThumbBit(instruction, *target) - reloc.value);
628 return llvm::Error::success();
629 default:
630 return llvm::make_error<GenericError>("unsupported arm relocation type");
631 }
632 return llvm::Error::success();
633 }
634
635 llvm::Error
getPairReferenceInfo(const normalized::Relocation & reloc1,const normalized::Relocation & reloc2,const DefinedAtom * inAtom,uint32_t offsetInAtom,uint64_t fixupAddress,bool isBig,bool scatterable,FindAtomBySectionAndAddress atomFromAddr,FindAtomBySymbolIndex atomFromSymbolIndex,Reference::KindValue * kind,const lld::Atom ** target,Reference::Addend * addend)636 ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
637 const normalized::Relocation &reloc2,
638 const DefinedAtom *inAtom,
639 uint32_t offsetInAtom,
640 uint64_t fixupAddress, bool isBig,
641 bool scatterable,
642 FindAtomBySectionAndAddress atomFromAddr,
643 FindAtomBySymbolIndex atomFromSymbolIndex,
644 Reference::KindValue *kind,
645 const lld::Atom **target,
646 Reference::Addend *addend) {
647 bool pointerDiff = false;
648 bool funcRel;
649 bool top;
650 bool thumbReloc;
651 switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
652 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo) << 16 |
653 ARM_RELOC_PAIR | rScattered | rLenThmbLo):
654 // ex: movw r1, :lower16:(_x-L1) [thumb mode]
655 *kind = thumb_movw_funcRel;
656 funcRel = true;
657 top = false;
658 thumbReloc = true;
659 break;
660 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi) << 16 |
661 ARM_RELOC_PAIR | rScattered | rLenThmbHi):
662 // ex: movt r1, :upper16:(_x-L1) [thumb mode]
663 *kind = thumb_movt_funcRel;
664 funcRel = true;
665 top = true;
666 thumbReloc = true;
667 break;
668 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo) << 16 |
669 ARM_RELOC_PAIR | rScattered | rLenArmLo):
670 // ex: movw r1, :lower16:(_x-L1) [arm mode]
671 *kind = arm_movw_funcRel;
672 funcRel = true;
673 top = false;
674 thumbReloc = false;
675 break;
676 case ((ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi) << 16 |
677 ARM_RELOC_PAIR | rScattered | rLenArmHi):
678 // ex: movt r1, :upper16:(_x-L1) [arm mode]
679 *kind = arm_movt_funcRel;
680 funcRel = true;
681 top = true;
682 thumbReloc = false;
683 break;
684 case ((ARM_RELOC_HALF | rLenThmbLo) << 16 |
685 ARM_RELOC_PAIR | rLenThmbLo):
686 // ex: movw r1, :lower16:_x [thumb mode]
687 *kind = thumb_movw;
688 funcRel = false;
689 top = false;
690 thumbReloc = true;
691 break;
692 case ((ARM_RELOC_HALF | rLenThmbHi) << 16 |
693 ARM_RELOC_PAIR | rLenThmbHi):
694 // ex: movt r1, :upper16:_x [thumb mode]
695 *kind = thumb_movt;
696 funcRel = false;
697 top = true;
698 thumbReloc = true;
699 break;
700 case ((ARM_RELOC_HALF | rLenArmLo) << 16 |
701 ARM_RELOC_PAIR | rLenArmLo):
702 // ex: movw r1, :lower16:_x [arm mode]
703 *kind = arm_movw;
704 funcRel = false;
705 top = false;
706 thumbReloc = false;
707 break;
708 case ((ARM_RELOC_HALF | rLenArmHi) << 16 |
709 ARM_RELOC_PAIR | rLenArmHi):
710 // ex: movt r1, :upper16:_x [arm mode]
711 *kind = arm_movt;
712 funcRel = false;
713 top = true;
714 thumbReloc = false;
715 break;
716 case ((ARM_RELOC_HALF | rScattered | rLenThmbLo) << 16 |
717 ARM_RELOC_PAIR | rLenThmbLo):
718 // ex: movw r1, :lower16:_x+a [thumb mode]
719 *kind = thumb_movw;
720 funcRel = false;
721 top = false;
722 thumbReloc = true;
723 break;
724 case ((ARM_RELOC_HALF | rScattered | rLenThmbHi) << 16 |
725 ARM_RELOC_PAIR | rLenThmbHi):
726 // ex: movt r1, :upper16:_x+a [thumb mode]
727 *kind = thumb_movt;
728 funcRel = false;
729 top = true;
730 thumbReloc = true;
731 break;
732 case ((ARM_RELOC_HALF | rScattered | rLenArmLo) << 16 |
733 ARM_RELOC_PAIR | rLenArmLo):
734 // ex: movw r1, :lower16:_x+a [arm mode]
735 *kind = arm_movw;
736 funcRel = false;
737 top = false;
738 thumbReloc = false;
739 break;
740 case ((ARM_RELOC_HALF | rScattered | rLenArmHi) << 16 |
741 ARM_RELOC_PAIR | rLenArmHi):
742 // ex: movt r1, :upper16:_x+a [arm mode]
743 *kind = arm_movt;
744 funcRel = false;
745 top = true;
746 thumbReloc = false;
747 break;
748 case ((ARM_RELOC_HALF | rExtern | rLenThmbLo) << 16 |
749 ARM_RELOC_PAIR | rLenThmbLo):
750 // ex: movw r1, :lower16:_undef [thumb mode]
751 *kind = thumb_movw;
752 funcRel = false;
753 top = false;
754 thumbReloc = true;
755 break;
756 case ((ARM_RELOC_HALF | rExtern | rLenThmbHi) << 16 |
757 ARM_RELOC_PAIR | rLenThmbHi):
758 // ex: movt r1, :upper16:_undef [thumb mode]
759 *kind = thumb_movt;
760 funcRel = false;
761 top = true;
762 thumbReloc = true;
763 break;
764 case ((ARM_RELOC_HALF | rExtern | rLenArmLo) << 16 |
765 ARM_RELOC_PAIR | rLenArmLo):
766 // ex: movw r1, :lower16:_undef [arm mode]
767 *kind = arm_movw;
768 funcRel = false;
769 top = false;
770 thumbReloc = false;
771 break;
772 case ((ARM_RELOC_HALF | rExtern | rLenArmHi) << 16 |
773 ARM_RELOC_PAIR | rLenArmHi):
774 // ex: movt r1, :upper16:_undef [arm mode]
775 *kind = arm_movt;
776 funcRel = false;
777 top = true;
778 thumbReloc = false;
779 break;
780 case ((ARM_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
781 ARM_RELOC_PAIR | rScattered | rLength4):
782 case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
783 ARM_RELOC_PAIR | rScattered | rLength4):
784 // ex: .long _foo - .
785 pointerDiff = true;
786 break;
787 default:
788 return llvm::make_error<GenericError>("unsupported arm relocation pair");
789 }
790 const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
791 uint32_t instruction = *(const ulittle32_t *)fixupContent;
792 uint32_t value;
793 uint32_t fromAddress;
794 uint32_t toAddress;
795 uint16_t instruction16;
796 uint16_t other16;
797 const lld::Atom *fromTarget;
798 Reference::Addend offsetInTo;
799 Reference::Addend offsetInFrom;
800 if (pointerDiff) {
801 toAddress = reloc1.value;
802 fromAddress = reloc2.value;
803 if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
804 return ec;
805 if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
806 return ec;
807 if (scatterable && (fromTarget != inAtom))
808 return llvm::make_error<GenericError>(
809 "SECTDIFF relocation where subtrahend label is not in atom");
810 *kind = delta32;
811 value = clearThumbBit(instruction, *target);
812 *addend = (int32_t)(value - (toAddress - fixupAddress));
813 } else if (funcRel) {
814 toAddress = reloc1.value;
815 fromAddress = reloc2.value;
816 if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
817 return ec;
818 if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
819 return ec;
820 if (fromTarget != inAtom)
821 return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
822 " where subtrahend label is not in atom");
823 other16 = (reloc2.offset & 0xFFFF);
824 if (thumbReloc) {
825 if (top) {
826 if (!isThumbMovt(instruction))
827 return llvm::make_error<GenericError>("expected movt instruction");
828 }
829 else {
830 if (!isThumbMovw(instruction))
831 return llvm::make_error<GenericError>("expected movw instruction");
832 }
833 instruction16 = getWordFromThumbMov(instruction);
834 }
835 else {
836 if (top) {
837 if (!isArmMovt(instruction))
838 return llvm::make_error<GenericError>("expected movt instruction");
839 }
840 else {
841 if (!isArmMovw(instruction))
842 return llvm::make_error<GenericError>("expected movw instruction");
843 }
844 instruction16 = getWordFromArmMov(instruction);
845 }
846 if (top)
847 value = (instruction16 << 16) | other16;
848 else
849 value = (other16 << 16) | instruction16;
850 value = clearThumbBit(value, *target);
851 int64_t ta = (int64_t) value - (toAddress - fromAddress);
852 *addend = ta - offsetInFrom;
853 return llvm::Error::success();
854 } else {
855 uint32_t sectIndex;
856 if (thumbReloc) {
857 if (top) {
858 if (!isThumbMovt(instruction))
859 return llvm::make_error<GenericError>("expected movt instruction");
860 }
861 else {
862 if (!isThumbMovw(instruction))
863 return llvm::make_error<GenericError>("expected movw instruction");
864 }
865 instruction16 = getWordFromThumbMov(instruction);
866 }
867 else {
868 if (top) {
869 if (!isArmMovt(instruction))
870 return llvm::make_error<GenericError>("expected movt instruction");
871 }
872 else {
873 if (!isArmMovw(instruction))
874 return llvm::make_error<GenericError>("expected movw instruction");
875 }
876 instruction16 = getWordFromArmMov(instruction);
877 }
878 other16 = (reloc2.offset & 0xFFFF);
879 if (top)
880 value = (instruction16 << 16) | other16;
881 else
882 value = (other16 << 16) | instruction16;
883 if (reloc1.isExtern) {
884 if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
885 return ec;
886 *addend = value;
887 } else {
888 if (reloc1.scattered) {
889 toAddress = reloc1.value;
890 sectIndex = 0;
891 } else {
892 toAddress = value;
893 sectIndex = reloc1.symbol;
894 }
895 if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
896 return ec;
897 *addend = value - toAddress;
898 }
899 }
900
901 return llvm::Error::success();
902 }
903
applyFixupFinal(const Reference & ref,uint8_t * loc,uint64_t fixupAddress,uint64_t targetAddress,uint64_t inAtomAddress,bool & thumbMode,bool targetIsThumb)904 void ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
905 uint64_t fixupAddress,
906 uint64_t targetAddress,
907 uint64_t inAtomAddress,
908 bool &thumbMode, bool targetIsThumb) {
909 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
910 return;
911 assert(ref.kindArch() == Reference::KindArch::ARM);
912 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
913 int32_t displacement;
914 uint16_t value16;
915 uint32_t value32;
916 switch (static_cast<ArmKind>(ref.kindValue())) {
917 case modeThumbCode:
918 thumbMode = true;
919 break;
920 case modeArmCode:
921 thumbMode = false;
922 break;
923 case modeData:
924 break;
925 case thumb_b22:
926 case thumb_bl22:
927 assert(thumbMode);
928 displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
929 value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
930 displacement, targetIsThumb);
931 *loc32 = value32;
932 break;
933 case thumb_movw:
934 assert(thumbMode);
935 value16 = (targetAddress + ref.addend()) & 0xFFFF;
936 if (targetIsThumb)
937 value16 |= 1;
938 *loc32 = setWordFromThumbMov(*loc32, value16);
939 break;
940 case thumb_movt:
941 assert(thumbMode);
942 value16 = (targetAddress + ref.addend()) >> 16;
943 *loc32 = setWordFromThumbMov(*loc32, value16);
944 break;
945 case thumb_movw_funcRel:
946 assert(thumbMode);
947 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
948 if (targetIsThumb)
949 value16 |= 1;
950 *loc32 = setWordFromThumbMov(*loc32, value16);
951 break;
952 case thumb_movt_funcRel:
953 assert(thumbMode);
954 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
955 *loc32 = setWordFromThumbMov(*loc32, value16);
956 break;
957 case arm_b24:
958 case arm_bl24:
959 assert(!thumbMode);
960 displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
961 value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
962 *loc32 = value32;
963 break;
964 case arm_movw:
965 assert(!thumbMode);
966 value16 = (targetAddress + ref.addend()) & 0xFFFF;
967 if (targetIsThumb)
968 value16 |= 1;
969 *loc32 = setWordFromArmMov(*loc32, value16);
970 break;
971 case arm_movt:
972 assert(!thumbMode);
973 value16 = (targetAddress + ref.addend()) >> 16;
974 *loc32 = setWordFromArmMov(*loc32, value16);
975 break;
976 case arm_movw_funcRel:
977 assert(!thumbMode);
978 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
979 if (targetIsThumb)
980 value16 |= 1;
981 *loc32 = setWordFromArmMov(*loc32, value16);
982 break;
983 case arm_movt_funcRel:
984 assert(!thumbMode);
985 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
986 *loc32 = setWordFromArmMov(*loc32, value16);
987 break;
988 case pointer32:
989 if (targetIsThumb)
990 *loc32 = targetAddress + ref.addend() + 1;
991 else
992 *loc32 = targetAddress + ref.addend();
993 break;
994 case delta32:
995 if (targetIsThumb)
996 *loc32 = targetAddress - fixupAddress + ref.addend() + 1;
997 else
998 *loc32 = targetAddress - fixupAddress + ref.addend();
999 break;
1000 case lazyPointer:
1001 // do nothing
1002 break;
1003 case lazyImmediateLocation:
1004 *loc32 = ref.addend();
1005 break;
1006 case invalid:
1007 llvm_unreachable("invalid ARM Reference Kind");
1008 break;
1009 }
1010 }
1011
generateAtomContent(const DefinedAtom & atom,bool relocatable,FindAddressForAtom findAddress,FindAddressForAtom findSectionAddress,uint64_t imageBaseAddress,llvm::MutableArrayRef<uint8_t> atomContentBuffer)1012 void ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
1013 bool relocatable,
1014 FindAddressForAtom findAddress,
1015 FindAddressForAtom findSectionAddress,
1016 uint64_t imageBaseAddress,
1017 llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
1018 // Copy raw bytes.
1019 std::copy(atom.rawContent().begin(), atom.rawContent().end(),
1020 atomContentBuffer.begin());
1021 // Apply fix-ups.
1022 bool thumbMode = false;
1023 for (const Reference *ref : atom) {
1024 uint32_t offset = ref->offsetInAtom();
1025 const Atom *target = ref->target();
1026 uint64_t targetAddress = 0;
1027 bool targetIsThumb = false;
1028 if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) {
1029 targetAddress = findAddress(*target);
1030 targetIsThumb = isThumbFunction(*defTarg);
1031 }
1032 uint64_t atomAddress = findAddress(atom);
1033 uint64_t fixupAddress = atomAddress + offset;
1034 if (relocatable) {
1035 applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
1036 targetAddress, atomAddress, thumbMode,
1037 targetIsThumb);
1038 } else {
1039 applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
1040 targetAddress, atomAddress, thumbMode, targetIsThumb);
1041 }
1042 }
1043 }
1044
useExternalRelocationTo(const Atom & target)1045 bool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
1046 // Undefined symbols are referenced via external relocations.
1047 if (isa<UndefinedAtom>(&target))
1048 return true;
1049 if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
1050 switch (defAtom->merge()) {
1051 case DefinedAtom::mergeAsTentative:
1052 // Tentative definitions are referenced via external relocations.
1053 return true;
1054 case DefinedAtom::mergeAsWeak:
1055 case DefinedAtom::mergeAsWeakAndAddressUsed:
1056 // Global weak-defs are referenced via external relocations.
1057 return (defAtom->scope() == DefinedAtom::scopeGlobal);
1058 default:
1059 break;
1060 }
1061 }
1062 // Everything else is reference via an internal relocation.
1063 return false;
1064 }
1065
applyFixupRelocatable(const Reference & ref,uint8_t * loc,uint64_t fixupAddress,uint64_t targetAddress,uint64_t inAtomAddress,bool & thumbMode,bool targetIsThumb)1066 void ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc,
1067 uint64_t fixupAddress,
1068 uint64_t targetAddress,
1069 uint64_t inAtomAddress,
1070 bool &thumbMode,
1071 bool targetIsThumb) {
1072 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
1073 return;
1074 assert(ref.kindArch() == Reference::KindArch::ARM);
1075 bool useExternalReloc = useExternalRelocationTo(*ref.target());
1076 ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
1077 int32_t displacement;
1078 uint16_t value16;
1079 uint32_t value32;
1080 bool targetIsUndef = isa<UndefinedAtom>(ref.target());
1081 switch (static_cast<ArmKind>(ref.kindValue())) {
1082 case modeThumbCode:
1083 thumbMode = true;
1084 break;
1085 case modeArmCode:
1086 thumbMode = false;
1087 break;
1088 case modeData:
1089 break;
1090 case thumb_b22:
1091 case thumb_bl22:
1092 assert(thumbMode);
1093 if (useExternalReloc)
1094 displacement = (ref.addend() - (fixupAddress + 4));
1095 else
1096 displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
1097 value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
1098 displacement,
1099 targetIsUndef || targetIsThumb);
1100 *loc32 = value32;
1101 break;
1102 case thumb_movw:
1103 assert(thumbMode);
1104 if (useExternalReloc)
1105 value16 = ref.addend() & 0xFFFF;
1106 else
1107 value16 = (targetAddress + ref.addend()) & 0xFFFF;
1108 *loc32 = setWordFromThumbMov(*loc32, value16);
1109 break;
1110 case thumb_movt:
1111 assert(thumbMode);
1112 if (useExternalReloc)
1113 value16 = ref.addend() >> 16;
1114 else
1115 value16 = (targetAddress + ref.addend()) >> 16;
1116 *loc32 = setWordFromThumbMov(*loc32, value16);
1117 break;
1118 case thumb_movw_funcRel:
1119 assert(thumbMode);
1120 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
1121 *loc32 = setWordFromThumbMov(*loc32, value16);
1122 break;
1123 case thumb_movt_funcRel:
1124 assert(thumbMode);
1125 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
1126 *loc32 = setWordFromThumbMov(*loc32, value16);
1127 break;
1128 case arm_b24:
1129 case arm_bl24:
1130 assert(!thumbMode);
1131 if (useExternalReloc)
1132 displacement = (ref.addend() - (fixupAddress + 8));
1133 else
1134 displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
1135 value32 = setDisplacementInArmBranch(*loc32, displacement,
1136 targetIsThumb);
1137 *loc32 = value32;
1138 break;
1139 case arm_movw:
1140 assert(!thumbMode);
1141 if (useExternalReloc)
1142 value16 = ref.addend() & 0xFFFF;
1143 else
1144 value16 = (targetAddress + ref.addend()) & 0xFFFF;
1145 *loc32 = setWordFromArmMov(*loc32, value16);
1146 break;
1147 case arm_movt:
1148 assert(!thumbMode);
1149 if (useExternalReloc)
1150 value16 = ref.addend() >> 16;
1151 else
1152 value16 = (targetAddress + ref.addend()) >> 16;
1153 *loc32 = setWordFromArmMov(*loc32, value16);
1154 break;
1155 case arm_movw_funcRel:
1156 assert(!thumbMode);
1157 value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
1158 *loc32 = setWordFromArmMov(*loc32, value16);
1159 break;
1160 case arm_movt_funcRel:
1161 assert(!thumbMode);
1162 value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
1163 *loc32 = setWordFromArmMov(*loc32, value16);
1164 break;
1165 case pointer32:
1166 *loc32 = targetAddress + ref.addend();
1167 break;
1168 case delta32:
1169 *loc32 = targetAddress - fixupAddress + ref.addend();
1170 break;
1171 case lazyPointer:
1172 case lazyImmediateLocation:
1173 // do nothing
1174 break;
1175 case invalid:
1176 llvm_unreachable("invalid ARM Reference Kind");
1177 break;
1178 }
1179 }
1180
appendSectionRelocations(const DefinedAtom & atom,uint64_t atomSectionOffset,const Reference & ref,FindSymbolIndexForAtom symbolIndexForAtom,FindSectionIndexForAtom sectionIndexForAtom,FindAddressForAtom addressForAtom,normalized::Relocations & relocs)1181 void ArchHandler_arm::appendSectionRelocations(
1182 const DefinedAtom &atom,
1183 uint64_t atomSectionOffset,
1184 const Reference &ref,
1185 FindSymbolIndexForAtom symbolIndexForAtom,
1186 FindSectionIndexForAtom sectionIndexForAtom,
1187 FindAddressForAtom addressForAtom,
1188 normalized::Relocations &relocs) {
1189 if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
1190 return;
1191 assert(ref.kindArch() == Reference::KindArch::ARM);
1192 uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
1193 bool useExternalReloc = useExternalRelocationTo(*ref.target());
1194 uint32_t targetAtomAddress;
1195 uint32_t fromAtomAddress;
1196 uint16_t other16;
1197 switch (static_cast<ArmKind>(ref.kindValue())) {
1198 case modeThumbCode:
1199 case modeArmCode:
1200 case modeData:
1201 // Do nothing.
1202 break;
1203 case thumb_b22:
1204 case thumb_bl22:
1205 if (useExternalReloc) {
1206 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1207 ARM_THUMB_RELOC_BR22 | rExtern | rPcRel | rLength4);
1208 } else {
1209 if (ref.addend() != 0)
1210 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1211 ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
1212 else
1213 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1214 ARM_THUMB_RELOC_BR22 | rPcRel | rLength4);
1215 }
1216 break;
1217 case thumb_movw:
1218 if (useExternalReloc) {
1219 other16 = ref.addend() >> 16;
1220 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1221 ARM_RELOC_HALF | rExtern | rLenThmbLo);
1222 appendReloc(relocs, other16, 0, 0,
1223 ARM_RELOC_PAIR | rLenThmbLo);
1224 } else {
1225 targetAtomAddress = addressForAtom(*ref.target());
1226 if (ref.addend() != 0) {
1227 other16 = (targetAtomAddress + ref.addend()) >> 16;
1228 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1229 ARM_RELOC_HALF | rScattered | rLenThmbLo);
1230 appendReloc(relocs, other16, 0, 0,
1231 ARM_RELOC_PAIR | rLenThmbLo);
1232 } else {
1233 other16 = (targetAtomAddress + ref.addend()) >> 16;
1234 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1235 ARM_RELOC_HALF | rLenThmbLo);
1236 appendReloc(relocs, other16, 0, 0,
1237 ARM_RELOC_PAIR | rLenThmbLo);
1238 }
1239 }
1240 break;
1241 case thumb_movt:
1242 if (useExternalReloc) {
1243 other16 = ref.addend() & 0xFFFF;
1244 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1245 ARM_RELOC_HALF | rExtern | rLenThmbHi);
1246 appendReloc(relocs, other16, 0, 0,
1247 ARM_RELOC_PAIR | rLenThmbHi);
1248 } else {
1249 targetAtomAddress = addressForAtom(*ref.target());
1250 if (ref.addend() != 0) {
1251 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1252 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1253 ARM_RELOC_HALF | rScattered | rLenThmbHi);
1254 appendReloc(relocs, other16, 0, 0,
1255 ARM_RELOC_PAIR | rLenThmbHi);
1256 } else {
1257 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1258 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1259 ARM_RELOC_HALF | rLenThmbHi);
1260 appendReloc(relocs, other16, 0, 0,
1261 ARM_RELOC_PAIR | rLenThmbHi);
1262 }
1263 }
1264 break;
1265 case thumb_movw_funcRel:
1266 fromAtomAddress = addressForAtom(atom);
1267 targetAtomAddress = addressForAtom(*ref.target());
1268 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
1269 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1270 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
1271 appendReloc(relocs, other16, 0, fromAtomAddress,
1272 ARM_RELOC_PAIR | rScattered | rLenThmbLo);
1273 break;
1274 case thumb_movt_funcRel:
1275 fromAtomAddress = addressForAtom(atom);
1276 targetAtomAddress = addressForAtom(*ref.target());
1277 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
1278 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1279 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
1280 appendReloc(relocs, other16, 0, fromAtomAddress,
1281 ARM_RELOC_PAIR | rScattered | rLenThmbHi);
1282 break;
1283 case arm_b24:
1284 case arm_bl24:
1285 if (useExternalReloc) {
1286 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1287 ARM_RELOC_BR24 | rExtern | rPcRel | rLength4);
1288 } else {
1289 if (ref.addend() != 0)
1290 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1291 ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
1292 else
1293 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1294 ARM_RELOC_BR24 | rPcRel | rLength4);
1295 }
1296 break;
1297 case arm_movw:
1298 if (useExternalReloc) {
1299 other16 = ref.addend() >> 16;
1300 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1301 ARM_RELOC_HALF | rExtern | rLenArmLo);
1302 appendReloc(relocs, other16, 0, 0,
1303 ARM_RELOC_PAIR | rLenArmLo);
1304 } else {
1305 targetAtomAddress = addressForAtom(*ref.target());
1306 if (ref.addend() != 0) {
1307 other16 = (targetAtomAddress + ref.addend()) >> 16;
1308 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1309 ARM_RELOC_HALF | rScattered | rLenArmLo);
1310 appendReloc(relocs, other16, 0, 0,
1311 ARM_RELOC_PAIR | rLenArmLo);
1312 } else {
1313 other16 = (targetAtomAddress + ref.addend()) >> 16;
1314 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1315 ARM_RELOC_HALF | rLenArmLo);
1316 appendReloc(relocs, other16, 0, 0,
1317 ARM_RELOC_PAIR | rLenArmLo);
1318 }
1319 }
1320 break;
1321 case arm_movt:
1322 if (useExternalReloc) {
1323 other16 = ref.addend() & 0xFFFF;
1324 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1325 ARM_RELOC_HALF | rExtern | rLenArmHi);
1326 appendReloc(relocs, other16, 0, 0,
1327 ARM_RELOC_PAIR | rLenArmHi);
1328 } else {
1329 targetAtomAddress = addressForAtom(*ref.target());
1330 if (ref.addend() != 0) {
1331 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1332 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1333 ARM_RELOC_HALF | rScattered | rLenArmHi);
1334 appendReloc(relocs, other16, 0, 0,
1335 ARM_RELOC_PAIR | rLenArmHi);
1336 } else {
1337 other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1338 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1339 ARM_RELOC_HALF | rLenArmHi);
1340 appendReloc(relocs, other16, 0, 0,
1341 ARM_RELOC_PAIR | rLenArmHi);
1342 }
1343 }
1344 break;
1345 case arm_movw_funcRel:
1346 fromAtomAddress = addressForAtom(atom);
1347 targetAtomAddress = addressForAtom(*ref.target());
1348 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
1349 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1350 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
1351 appendReloc(relocs, other16, 0, fromAtomAddress,
1352 ARM_RELOC_PAIR | rScattered | rLenArmLo);
1353 break;
1354 case arm_movt_funcRel:
1355 fromAtomAddress = addressForAtom(atom);
1356 targetAtomAddress = addressForAtom(*ref.target());
1357 other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
1358 appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1359 ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
1360 appendReloc(relocs, other16, 0, fromAtomAddress,
1361 ARM_RELOC_PAIR | rScattered | rLenArmHi);
1362 break;
1363 case pointer32:
1364 if (useExternalReloc) {
1365 appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1366 ARM_RELOC_VANILLA | rExtern | rLength4);
1367 }
1368 else {
1369 if (ref.addend() != 0)
1370 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1371 ARM_RELOC_VANILLA | rScattered | rLength4);
1372 else
1373 appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1374 ARM_RELOC_VANILLA | rLength4);
1375 }
1376 break;
1377 case delta32:
1378 appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1379 ARM_RELOC_SECTDIFF | rScattered | rLength4);
1380 appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
1381 ref.offsetInAtom(),
1382 ARM_RELOC_PAIR | rScattered | rLength4);
1383 break;
1384 case lazyPointer:
1385 case lazyImmediateLocation:
1386 // do nothing
1387 break;
1388 case invalid:
1389 llvm_unreachable("invalid ARM Reference Kind");
1390 break;
1391 }
1392 }
1393
addAdditionalReferences(MachODefinedAtom & atom)1394 void ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
1395 if (atom.isThumb()) {
1396 atom.addReference(Reference::KindNamespace::mach_o,
1397 Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
1398 }
1399 }
1400
isThumbFunction(const DefinedAtom & atom)1401 bool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
1402 for (const Reference *ref : atom) {
1403 if (ref->offsetInAtom() != 0)
1404 return false;
1405 if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
1406 continue;
1407 assert(ref->kindArch() == Reference::KindArch::ARM);
1408 if (ref->kindValue() == modeThumbCode)
1409 return true;
1410 }
1411 return false;
1412 }
1413
1414 class Thumb2ToArmShimAtom : public SimpleDefinedAtom {
1415 public:
Thumb2ToArmShimAtom(MachOFile & file,StringRef targetName,const DefinedAtom & target)1416 Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
1417 const DefinedAtom &target)
1418 : SimpleDefinedAtom(file) {
1419 addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
1420 ArchHandler_arm::modeThumbCode, 0, this, 0);
1421 addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
1422 ArchHandler_arm::delta32, 8, &target, 0);
1423 std::string name = std::string(targetName) + "$shim";
1424 StringRef tmp(name);
1425 _name = tmp.copy(file.allocator());
1426 }
1427
1428 ~Thumb2ToArmShimAtom() override = default;
1429
name() const1430 StringRef name() const override {
1431 return _name;
1432 }
1433
contentType() const1434 ContentType contentType() const override {
1435 return DefinedAtom::typeCode;
1436 }
1437
alignment() const1438 Alignment alignment() const override { return 4; }
1439
size() const1440 uint64_t size() const override {
1441 return 12;
1442 }
1443
permissions() const1444 ContentPermissions permissions() const override {
1445 return DefinedAtom::permR_X;
1446 }
1447
rawContent() const1448 ArrayRef<uint8_t> rawContent() const override {
1449 static const uint8_t bytes[] =
1450 { 0xDF, 0xF8, 0x04, 0xC0, // ldr ip, pc + 4
1451 0xFF, 0x44, // add ip, pc, ip
1452 0x60, 0x47, // ldr pc, [ip]
1453 0x00, 0x00, 0x00, 0x00 }; // .long target - this
1454 assert(sizeof(bytes) == size());
1455 return llvm::makeArrayRef(bytes, sizeof(bytes));
1456 }
1457 private:
1458 StringRef _name;
1459 };
1460
1461 class ArmToThumbShimAtom : public SimpleDefinedAtom {
1462 public:
ArmToThumbShimAtom(MachOFile & file,StringRef targetName,const DefinedAtom & target)1463 ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
1464 const DefinedAtom &target)
1465 : SimpleDefinedAtom(file) {
1466 addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
1467 ArchHandler_arm::delta32, 12, &target, 0);
1468 std::string name = std::string(targetName) + "$shim";
1469 StringRef tmp(name);
1470 _name = tmp.copy(file.allocator());
1471 }
1472
1473 ~ArmToThumbShimAtom() override = default;
1474
name() const1475 StringRef name() const override {
1476 return _name;
1477 }
1478
contentType() const1479 ContentType contentType() const override {
1480 return DefinedAtom::typeCode;
1481 }
1482
alignment() const1483 Alignment alignment() const override { return 4; }
1484
size() const1485 uint64_t size() const override {
1486 return 16;
1487 }
1488
permissions() const1489 ContentPermissions permissions() const override {
1490 return DefinedAtom::permR_X;
1491 }
1492
rawContent() const1493 ArrayRef<uint8_t> rawContent() const override {
1494 static const uint8_t bytes[] =
1495 { 0x04, 0xC0, 0x9F, 0xE5, // ldr ip, pc + 4
1496 0x0C, 0xC0, 0x8F, 0xE0, // add ip, pc, ip
1497 0x1C, 0xFF, 0x2F, 0xE1, // ldr pc, [ip]
1498 0x00, 0x00, 0x00, 0x00 }; // .long target - this
1499 assert(sizeof(bytes) == size());
1500 return llvm::makeArrayRef(bytes, sizeof(bytes));
1501 }
1502 private:
1503 StringRef _name;
1504 };
1505
createShim(MachOFile & file,bool thumbToArm,const DefinedAtom & target)1506 const DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
1507 bool thumbToArm,
1508 const DefinedAtom &target) {
1509 bool isStub = (target.contentType() == DefinedAtom::typeStub);
1510 StringRef targetName = isStub ? stubName(target) : target.name();
1511 if (thumbToArm)
1512 return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
1513 else
1514 return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
1515 }
1516
create_arm()1517 std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
1518 return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
1519 }
1520
1521 } // namespace mach_o
1522 } // namespace lld
1523