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