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