• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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