1280461Sdim//===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===//
2280461Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6280461Sdim//
7280461Sdim//===----------------------------------------------------------------------===//
8280461Sdim
9280461Sdim#include "ArchHandler.h"
10280461Sdim#include "Atoms.h"
11280461Sdim#include "MachONormalizedFileBinaryUtils.h"
12280461Sdim#include "llvm/ADT/StringRef.h"
13280461Sdim#include "llvm/ADT/StringSwitch.h"
14280461Sdim#include "llvm/ADT/Triple.h"
15280461Sdim#include "llvm/Support/Endian.h"
16280461Sdim#include "llvm/Support/ErrorHandling.h"
17280461Sdim
18280461Sdimusing namespace llvm::MachO;
19280461Sdimusing namespace lld::mach_o::normalized;
20280461Sdim
21280461Sdimnamespace lld {
22280461Sdimnamespace mach_o {
23280461Sdim
24280461Sdimusing llvm::support::ulittle32_t;
25280461Sdimusing llvm::support::little32_t;
26280461Sdim
27280461Sdim
28280461Sdimclass ArchHandler_arm : public ArchHandler {
29280461Sdimpublic:
30292934Sdim  ArchHandler_arm() = default;
31292934Sdim  ~ArchHandler_arm() override = default;
32280461Sdim
33280461Sdim  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
34280461Sdim
35280461Sdim  Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
36280461Sdim
37280461Sdim  const ArchHandler::StubInfo &stubInfo() override;
38280461Sdim  bool isCallSite(const Reference &) override;
39280461Sdim  bool isPointer(const Reference &) override;
40280461Sdim  bool isPairedReloc(const normalized::Relocation &) override;
41280461Sdim  bool isNonCallBranch(const Reference &) override;
42280461Sdim
43280461Sdim  bool needsCompactUnwind() override {
44280461Sdim    return false;
45280461Sdim  }
46280461Sdim  Reference::KindValue imageOffsetKind() override {
47280461Sdim    return invalid;
48280461Sdim  }
49280461Sdim  Reference::KindValue imageOffsetKindIndirect() override {
50280461Sdim    return invalid;
51280461Sdim  }
52280461Sdim
53303239Sdim  Reference::KindValue unwindRefToPersonalityFunctionKind() override {
54303239Sdim    return invalid;
55303239Sdim  }
56303239Sdim
57280461Sdim  Reference::KindValue unwindRefToCIEKind() override {
58280461Sdim    return invalid;
59280461Sdim  }
60280461Sdim
61280461Sdim  Reference::KindValue unwindRefToFunctionKind() override {
62280461Sdim    return invalid;
63280461Sdim  }
64280461Sdim
65280461Sdim  Reference::KindValue unwindRefToEhFrameKind() override {
66280461Sdim    return invalid;
67280461Sdim  }
68280461Sdim
69326909Sdim  Reference::KindValue lazyImmediateLocationKind() override {
70326909Sdim    return lazyImmediateLocation;
71326909Sdim  }
72326909Sdim
73303239Sdim  Reference::KindValue pointerKind() override {
74303239Sdim    return invalid;
75303239Sdim  }
76303239Sdim
77280461Sdim  uint32_t dwarfCompactUnwindType() override {
78280461Sdim    // FIXME
79280461Sdim    return -1;
80280461Sdim  }
81280461Sdim
82303239Sdim  llvm::Error getReferenceInfo(const normalized::Relocation &reloc,
83303239Sdim                               const DefinedAtom *inAtom,
84303239Sdim                               uint32_t offsetInAtom,
85303239Sdim                               uint64_t fixupAddress, bool swap,
86303239Sdim                               FindAtomBySectionAndAddress atomFromAddress,
87303239Sdim                               FindAtomBySymbolIndex atomFromSymbolIndex,
88303239Sdim                               Reference::KindValue *kind,
89303239Sdim                               const lld::Atom **target,
90303239Sdim                               Reference::Addend *addend) override;
91303239Sdim  llvm::Error
92280461Sdim      getPairReferenceInfo(const normalized::Relocation &reloc1,
93280461Sdim                           const normalized::Relocation &reloc2,
94280461Sdim                           const DefinedAtom *inAtom,
95280461Sdim                           uint32_t offsetInAtom,
96280461Sdim                           uint64_t fixupAddress, bool swap, bool scatterable,
97280461Sdim                           FindAtomBySectionAndAddress atomFromAddress,
98280461Sdim                           FindAtomBySymbolIndex atomFromSymbolIndex,
99280461Sdim                           Reference::KindValue *kind,
100280461Sdim                           const lld::Atom **target,
101280461Sdim                           Reference::Addend *addend) override;
102280461Sdim
103280461Sdim  void generateAtomContent(const DefinedAtom &atom, bool relocatable,
104280461Sdim                           FindAddressForAtom findAddress,
105280461Sdim                           FindAddressForAtom findSectionAddress,
106280461Sdim                           uint64_t imageBaseAddress,
107303239Sdim                           llvm::MutableArrayRef<uint8_t> atomContentBuffer) override;
108280461Sdim
109280461Sdim  void appendSectionRelocations(const DefinedAtom &atom,
110280461Sdim                                uint64_t atomSectionOffset,
111280461Sdim                                const Reference &ref,
112280461Sdim                                FindSymbolIndexForAtom,
113280461Sdim                                FindSectionIndexForAtom,
114280461Sdim                                FindAddressForAtom,
115280461Sdim                                normalized::Relocations &) override;
116280461Sdim
117280461Sdim  void addAdditionalReferences(MachODefinedAtom &atom) override;
118280461Sdim
119280461Sdim  bool isDataInCodeTransition(Reference::KindValue refKind) override {
120280461Sdim    switch (refKind) {
121280461Sdim    case modeThumbCode:
122280461Sdim    case modeArmCode:
123280461Sdim    case modeData:
124280461Sdim      return true;
125280461Sdim    default:
126280461Sdim      return false;
127280461Sdim      break;
128280461Sdim    }
129280461Sdim  }
130280461Sdim
131280461Sdim  Reference::KindValue dataInCodeTransitionStart(
132280461Sdim                                        const MachODefinedAtom &atom) override {
133280461Sdim    return modeData;
134280461Sdim  }
135280461Sdim
136280461Sdim  Reference::KindValue dataInCodeTransitionEnd(
137280461Sdim                                        const MachODefinedAtom &atom) override {
138280461Sdim    return atom.isThumb() ? modeThumbCode : modeArmCode;
139280461Sdim  }
140280461Sdim
141280461Sdim  bool isThumbFunction(const DefinedAtom &atom) override;
142280461Sdim  const DefinedAtom *createShim(MachOFile &file, bool thumbToArm,
143280461Sdim                                const DefinedAtom &) override;
144280461Sdim
145280461Sdimprivate:
146280461Sdim  friend class Thumb2ToArmShimAtom;
147280461Sdim  friend class ArmToThumbShimAtom;
148280461Sdim
149280461Sdim  static const Registry::KindStrings _sKindStrings[];
150280461Sdim  static const StubInfo              _sStubInfoArmPIC;
151280461Sdim
152280461Sdim  enum ArmKind : Reference::KindValue {
153280461Sdim    invalid,               /// for error condition
154280461Sdim
155280461Sdim    modeThumbCode,         /// Content starting at this offset is thumb.
156280461Sdim    modeArmCode,           /// Content starting at this offset is arm.
157280461Sdim    modeData,              /// Content starting at this offset is data.
158280461Sdim
159280461Sdim    // Kinds found in mach-o .o files:
160280461Sdim    thumb_bl22,            /// ex: bl _foo
161280461Sdim    thumb_b22,             /// ex: b _foo
162280461Sdim    thumb_movw,            /// ex: movw	r1, :lower16:_foo
163280461Sdim    thumb_movt,            /// ex: movt	r1, :lower16:_foo
164280461Sdim    thumb_movw_funcRel,    /// ex: movw	r1, :lower16:(_foo-(L1+4))
165280461Sdim    thumb_movt_funcRel,    /// ex: movt r1, :upper16:(_foo-(L1+4))
166280461Sdim    arm_bl24,              /// ex: bl _foo
167280461Sdim    arm_b24,               /// ex: b _foo
168280461Sdim    arm_movw,              /// ex: movw	r1, :lower16:_foo
169280461Sdim    arm_movt,              /// ex: movt	r1, :lower16:_foo
170280461Sdim    arm_movw_funcRel,      /// ex: movw	r1, :lower16:(_foo-(L1+4))
171280461Sdim    arm_movt_funcRel,      /// ex: movt r1, :upper16:(_foo-(L1+4))
172280461Sdim    pointer32,             /// ex: .long _foo
173280461Sdim    delta32,               /// ex: .long _foo - .
174280461Sdim
175280461Sdim    // Kinds introduced by Passes:
176280461Sdim    lazyPointer,           /// Location contains a lazy pointer.
177280461Sdim    lazyImmediateLocation, /// Location contains immediate value used in stub.
178280461Sdim  };
179280461Sdim
180280461Sdim  // Utility functions for inspecting/updating instructions.
181280461Sdim  static bool isThumbMovw(uint32_t instruction);
182280461Sdim  static bool isThumbMovt(uint32_t instruction);
183280461Sdim  static bool isArmMovw(uint32_t instruction);
184280461Sdim  static bool isArmMovt(uint32_t instruction);
185280461Sdim  static int32_t getDisplacementFromThumbBranch(uint32_t instruction, uint32_t);
186280461Sdim  static int32_t getDisplacementFromArmBranch(uint32_t instruction);
187280461Sdim  static uint16_t getWordFromThumbMov(uint32_t instruction);
188280461Sdim  static uint16_t getWordFromArmMov(uint32_t instruction);
189280461Sdim  static uint32_t clearThumbBit(uint32_t value, const Atom *target);
190280461Sdim  static uint32_t setDisplacementInArmBranch(uint32_t instr, int32_t disp,
191280461Sdim                                             bool targetIsThumb);
192280461Sdim  static uint32_t setDisplacementInThumbBranch(uint32_t instr, uint32_t ia,
193280461Sdim                                               int32_t disp, bool targetThumb);
194280461Sdim  static uint32_t setWordFromThumbMov(uint32_t instruction, uint16_t word);
195280461Sdim  static uint32_t setWordFromArmMov(uint32_t instruction, uint16_t word);
196280461Sdim
197280461Sdim  StringRef stubName(const DefinedAtom &);
198280461Sdim  bool useExternalRelocationTo(const Atom &target);
199280461Sdim
200280461Sdim  void applyFixupFinal(const Reference &ref, uint8_t *location,
201280461Sdim                       uint64_t fixupAddress, uint64_t targetAddress,
202280461Sdim                       uint64_t inAtomAddress, bool &thumbMode,
203280461Sdim                       bool targetIsThumb);
204280461Sdim
205280461Sdim  void applyFixupRelocatable(const Reference &ref, uint8_t *location,
206280461Sdim                             uint64_t fixupAddress,
207280461Sdim                             uint64_t targetAddress,
208280461Sdim                             uint64_t inAtomAddress, bool &thumbMode,
209280461Sdim                             bool targetIsThumb);
210280461Sdim};
211280461Sdim
212280461Sdim//===----------------------------------------------------------------------===//
213280461Sdim//  ArchHandler_arm
214280461Sdim//===----------------------------------------------------------------------===//
215280461Sdim
216280461Sdimconst Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
217280461Sdim  LLD_KIND_STRING_ENTRY(invalid),
218280461Sdim  LLD_KIND_STRING_ENTRY(modeThumbCode),
219280461Sdim  LLD_KIND_STRING_ENTRY(modeArmCode),
220280461Sdim  LLD_KIND_STRING_ENTRY(modeData),
221280461Sdim  LLD_KIND_STRING_ENTRY(thumb_bl22),
222280461Sdim  LLD_KIND_STRING_ENTRY(thumb_b22),
223280461Sdim  LLD_KIND_STRING_ENTRY(thumb_movw),
224280461Sdim  LLD_KIND_STRING_ENTRY(thumb_movt),
225280461Sdim  LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
226280461Sdim  LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
227280461Sdim  LLD_KIND_STRING_ENTRY(arm_bl24),
228280461Sdim  LLD_KIND_STRING_ENTRY(arm_b24),
229280461Sdim  LLD_KIND_STRING_ENTRY(arm_movw),
230280461Sdim  LLD_KIND_STRING_ENTRY(arm_movt),
231280461Sdim  LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
232280461Sdim  LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
233280461Sdim  LLD_KIND_STRING_ENTRY(pointer32),
234280461Sdim  LLD_KIND_STRING_ENTRY(delta32),
235280461Sdim  LLD_KIND_STRING_ENTRY(lazyPointer),
236280461Sdim  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
237280461Sdim  LLD_KIND_STRING_END
238280461Sdim};
239280461Sdim
240280461Sdimconst ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
241280461Sdim  "dyld_stub_binder",
242280461Sdim
243280461Sdim  // References in lazy pointer
244280461Sdim  { Reference::KindArch::ARM, pointer32, 0, 0 },
245280461Sdim  { Reference::KindArch::ARM, lazyPointer, 0, 0 },
246280461Sdim
247280461Sdim  // GOT pointer to dyld_stub_binder
248280461Sdim  { Reference::KindArch::ARM, pointer32, 0, 0 },
249280461Sdim
250280461Sdim  // arm code alignment 2^2
251280461Sdim  2,
252280461Sdim
253280461Sdim  // Stub size and code
254280461Sdim  16,
255280461Sdim  { 0x04, 0xC0, 0x9F, 0xE5,       // 	ldr ip, pc + 12
256280461Sdim    0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
257280461Sdim    0x00, 0xF0, 0x9C, 0xE5,       // 	ldr pc, [ip]
258280461Sdim    0x00, 0x00, 0x00, 0x00 },     // 	.long L_foo$lazy_ptr - (L1$scv + 8)
259280461Sdim  { Reference::KindArch::ARM, delta32, 12, 0 },
260280461Sdim  { false, 0, 0, 0 },
261280461Sdim
262280461Sdim  // Stub Helper size and code
263280461Sdim  12,
264280461Sdim  { 0x00, 0xC0, 0x9F, 0xE5,       // ldr   ip, [pc, #0]
265280461Sdim    0x00, 0x00, 0x00, 0xEA,       // b	     _helperhelper
266280461Sdim    0x00, 0x00, 0x00, 0x00 },     // .long  lazy-info-offset
267280461Sdim  { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
268280461Sdim  { Reference::KindArch::ARM, arm_b24, 4, 0 },
269280461Sdim
270303239Sdim  // Stub helper image cache content type
271303239Sdim  DefinedAtom::typeGOT,
272303239Sdim
273280461Sdim  // Stub Helper-Common size and code
274280461Sdim  36,
275303239Sdim  // Stub helper alignment
276303239Sdim  2,
277280461Sdim	{ // push lazy-info-offset
278280461Sdim    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
279280461Sdim		// push address of dyld_mageLoaderCache
280280461Sdim    0x10, 0xC0, 0x9F, 0xE5,       // ldr	ip, L1
281280461Sdim    0x0C, 0xC0, 0x8F, 0xE0,       // add	ip, pc, ip
282280461Sdim    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
283280461Sdim		// jump through dyld_stub_binder
284280461Sdim    0x08, 0xC0, 0x9F, 0xE5,       // ldr	ip, L2
285280461Sdim    0x0C, 0xC0, 0x8F, 0xE0,       // add	ip, pc, ip
286280461Sdim    0x00, 0xF0, 0x9C, 0xE5,       // ldr	pc, [ip]
287280461Sdim    0x00, 0x00, 0x00, 0x00,       // L1: .long fFastStubGOTAtom - (helper+16)
288280461Sdim    0x00, 0x00, 0x00, 0x00 },     // L2: .long dyld_stub_binder - (helper+28)
289280461Sdim  { Reference::KindArch::ARM, delta32, 28, 0xC },
290280461Sdim  { false, 0, 0, 0 },
291280461Sdim  { Reference::KindArch::ARM, delta32, 32, 0x04 },
292280461Sdim  { false, 0, 0, 0 }
293280461Sdim};
294280461Sdim
295280461Sdimconst ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
296280461Sdim  // If multiple kinds of stubs are supported, select which StubInfo here.
297280461Sdim  return _sStubInfoArmPIC;
298280461Sdim}
299280461Sdim
300280461Sdimbool ArchHandler_arm::isCallSite(const Reference &ref) {
301280461Sdim  switch (ref.kindValue()) {
302280461Sdim  case thumb_b22:
303280461Sdim  case thumb_bl22:
304280461Sdim  case arm_b24:
305280461Sdim  case arm_bl24:
306280461Sdim    return true;
307280461Sdim  default:
308280461Sdim    return false;
309280461Sdim  }
310280461Sdim}
311280461Sdim
312280461Sdimbool ArchHandler_arm::isPointer(const Reference &ref) {
313280461Sdim  return (ref.kindValue() == pointer32);
314280461Sdim}
315280461Sdim
316280461Sdimbool ArchHandler_arm::isNonCallBranch(const Reference &ref) {
317280461Sdim  switch (ref.kindValue()) {
318280461Sdim  case thumb_b22:
319280461Sdim  case arm_b24:
320280461Sdim    return true;
321280461Sdim  default:
322280461Sdim    return false;
323280461Sdim  }
324280461Sdim}
325280461Sdim
326280461Sdimbool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
327280461Sdim  switch (reloc.type) {
328280461Sdim  case ARM_RELOC_SECTDIFF:
329280461Sdim  case ARM_RELOC_LOCAL_SECTDIFF:
330280461Sdim  case ARM_RELOC_HALF_SECTDIFF:
331280461Sdim  case ARM_RELOC_HALF:
332280461Sdim    return true;
333280461Sdim  default:
334280461Sdim    return false;
335280461Sdim  }
336280461Sdim}
337280461Sdim
338280461Sdim/// Trace references from stub atom to lazy pointer to target and get its name.
339280461SdimStringRef ArchHandler_arm::stubName(const DefinedAtom &stubAtom) {
340280461Sdim  assert(stubAtom.contentType() == DefinedAtom::typeStub);
341280461Sdim  for (const Reference *ref : stubAtom) {
342280461Sdim    if (const DefinedAtom* lp = dyn_cast<DefinedAtom>(ref->target())) {
343280461Sdim      if (lp->contentType() != DefinedAtom::typeLazyPointer)
344280461Sdim        continue;
345280461Sdim      for (const Reference *ref2 : *lp) {
346280461Sdim        if (ref2->kindValue() != lazyPointer)
347280461Sdim          continue;
348280461Sdim        return ref2->target()->name();
349280461Sdim      }
350280461Sdim    }
351280461Sdim  }
352280461Sdim  return "stub";
353280461Sdim}
354280461Sdim
355280461Sdim/// Extract displacement from an ARM b/bl/blx instruction.
356280461Sdimint32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
357280461Sdim  // Sign-extend imm24
358280461Sdim  int32_t displacement = (instruction & 0x00FFFFFF) << 2;
359280461Sdim  if ((displacement & 0x02000000) != 0)
360280461Sdim    displacement |= 0xFC000000;
361280461Sdim  // If this is BLX and H bit set, add 2.
362280461Sdim  if ((instruction & 0xFF000000) == 0xFB000000)
363280461Sdim    displacement += 2;
364280461Sdim  return displacement;
365280461Sdim}
366280461Sdim
367280461Sdim/// Update an ARM b/bl/blx instruction, switching bl <-> blx as needed.
368280461Sdimuint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
369280461Sdim                                                     int32_t displacement,
370280461Sdim                                                     bool targetIsThumb) {
371280461Sdim  assert((displacement <= 33554428) && (displacement > (-33554432))
372280461Sdim                                              && "arm branch out of range");
373280461Sdim  bool is_blx = ((instruction & 0xF0000000) == 0xF0000000);
374280461Sdim  uint32_t newInstruction = (instruction & 0xFF000000);
375280461Sdim  uint32_t h = 0;
376280461Sdim  if (targetIsThumb) {
377280461Sdim    // Force use of BLX.
378280461Sdim    newInstruction = 0xFA000000;
379280461Sdim    if (!is_blx) {
380280461Sdim      assert(((instruction & 0xF0000000) == 0xE0000000)
381280461Sdim                                                   && "no conditional arm blx");
382280461Sdim      assert(((instruction & 0xFF000000) == 0xEB000000)
383280461Sdim                                             && "no arm pc-rel BX instruction");
384280461Sdim    }
385280461Sdim    if (displacement & 2)
386280461Sdim      h = 1;
387280461Sdim  }
388280461Sdim  else {
389280461Sdim    // Force use of B/BL.
390280461Sdim    if (is_blx)
391280461Sdim      newInstruction = 0xEB000000;
392280461Sdim  }
393280461Sdim  newInstruction |= (h << 24) | ((displacement >> 2) & 0x00FFFFFF);
394280461Sdim  return newInstruction;
395280461Sdim}
396280461Sdim
397280461Sdim/// Extract displacement from a thumb b/bl/blx instruction.
398280461Sdimint32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction,
399280461Sdim                                                        uint32_t instrAddr) {
400280461Sdim  bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
401280461Sdim  uint32_t s = (instruction >> 10) & 0x1;
402280461Sdim  uint32_t j1 = (instruction >> 29) & 0x1;
403280461Sdim  uint32_t j2 = (instruction >> 27) & 0x1;
404280461Sdim  uint32_t imm10 = instruction & 0x3FF;
405280461Sdim  uint32_t imm11 = (instruction >> 16) & 0x7FF;
406280461Sdim  uint32_t i1 = (j1 == s);
407280461Sdim  uint32_t i2 = (j2 == s);
408280461Sdim  uint32_t dis =
409280461Sdim      (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
410280461Sdim  int32_t sdis = dis;
411280461Sdim  int32_t result = s ? (sdis | 0xFE000000) : sdis;
412280461Sdim  if (is_blx && (instrAddr & 0x2)) {
413280461Sdim    // The thumb blx instruction always has low bit of imm11 as zero.  The way
414280461Sdim    // a 2-byte aligned blx can branch to a 4-byte aligned ARM target is that
415280461Sdim    // the blx instruction always 4-byte aligns the pc before adding the
416280461Sdim    // displacement from the blx.  We must emulate that when decoding this.
417280461Sdim    result -= 2;
418280461Sdim  }
419280461Sdim  return result;
420280461Sdim}
421280461Sdim
422280461Sdim/// Update a thumb b/bl/blx instruction, switching bl <-> blx as needed.
423280461Sdimuint32_t ArchHandler_arm::setDisplacementInThumbBranch(uint32_t instruction,
424280461Sdim                                                       uint32_t instrAddr,
425280461Sdim                                                       int32_t displacement,
426280461Sdim                                                       bool targetIsThumb) {
427280461Sdim  assert((displacement <= 16777214) && (displacement > (-16777216))
428280461Sdim                                              && "thumb branch out of range");
429280461Sdim	bool is_bl = ((instruction & 0xD000F800) == 0xD000F000);
430280461Sdim	bool is_blx = ((instruction & 0xD000F800) == 0xC000F000);
431280461Sdim	bool is_b = ((instruction & 0xD000F800) == 0x9000F000);
432280461Sdim  uint32_t newInstruction = (instruction & 0xD000F800);
433280461Sdim  if (is_bl || is_blx) {
434280461Sdim    if (targetIsThumb) {
435280461Sdim      newInstruction = 0xD000F000; // Use bl
436280461Sdim    } else {
437280461Sdim      newInstruction = 0xC000F000; // Use blx
438280461Sdim      // See note in getDisplacementFromThumbBranch() about blx.
439280461Sdim      if (instrAddr & 0x2)
440280461Sdim        displacement += 2;
441280461Sdim    }
442280461Sdim  } else if (is_b) {
443280461Sdim    assert(targetIsThumb && "no pc-rel thumb branch instruction that "
444280461Sdim                             "switches to arm mode");
445280461Sdim  }
446280461Sdim  else {
447280461Sdim    llvm_unreachable("thumb branch22 reloc on a non-branch instruction");
448280461Sdim  }
449280461Sdim  uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
450280461Sdim  uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
451280461Sdim  uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
452280461Sdim  uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
453280461Sdim  uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
454280461Sdim  uint32_t j1 = (i1 == s);
455280461Sdim  uint32_t j2 = (i2 == s);
456280461Sdim  uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
457280461Sdim  uint32_t firstDisp = (s << 10) | imm10;
458280461Sdim  newInstruction |= (nextDisp << 16) | firstDisp;
459280461Sdim  return newInstruction;
460280461Sdim}
461280461Sdim
462280461Sdimbool ArchHandler_arm::isThumbMovw(uint32_t instruction) {
463280461Sdim  return (instruction & 0x8000FBF0) == 0x0000F240;
464280461Sdim}
465280461Sdim
466280461Sdimbool ArchHandler_arm::isThumbMovt(uint32_t instruction) {
467280461Sdim  return (instruction & 0x8000FBF0) == 0x0000F2C0;
468280461Sdim}
469280461Sdim
470280461Sdimbool ArchHandler_arm::isArmMovw(uint32_t instruction) {
471280461Sdim  return (instruction & 0x0FF00000) == 0x03000000;
472280461Sdim}
473280461Sdim
474280461Sdimbool ArchHandler_arm::isArmMovt(uint32_t instruction) {
475280461Sdim  return (instruction & 0x0FF00000) == 0x03400000;
476280461Sdim}
477280461Sdim
478280461Sdimuint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
479280461Sdim  assert(isThumbMovw(instruction) || isThumbMovt(instruction));
480280461Sdim  uint32_t i = ((instruction & 0x00000400) >> 10);
481280461Sdim  uint32_t imm4 = (instruction & 0x0000000F);
482280461Sdim  uint32_t imm3 = ((instruction & 0x70000000) >> 28);
483280461Sdim  uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
484280461Sdim  return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
485280461Sdim}
486280461Sdim
487280461Sdimuint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
488280461Sdim  assert(isArmMovw(instruction) || isArmMovt(instruction));
489280461Sdim  uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
490280461Sdim  uint32_t imm12 = (instruction & 0x00000FFF);
491280461Sdim  return (imm4 << 12) | imm12;
492280461Sdim}
493280461Sdim
494280461Sdimuint32_t ArchHandler_arm::setWordFromThumbMov(uint32_t instr, uint16_t word) {
495280461Sdim  assert(isThumbMovw(instr) || isThumbMovt(instr));
496280461Sdim  uint32_t imm4 = (word & 0xF000) >> 12;
497280461Sdim  uint32_t i =    (word & 0x0800) >> 11;
498280461Sdim  uint32_t imm3 = (word & 0x0700) >> 8;
499280461Sdim  uint32_t imm8 =  word & 0x00FF;
500280461Sdim	return (instr & 0x8F00FBF0) | imm4 | (i << 10) | (imm3 << 28) | (imm8 << 16);
501280461Sdim}
502280461Sdim
503280461Sdimuint32_t ArchHandler_arm::setWordFromArmMov(uint32_t instr, uint16_t word) {
504280461Sdim  assert(isArmMovw(instr) || isArmMovt(instr));
505280461Sdim  uint32_t imm4 = (word & 0xF000) >> 12;
506280461Sdim  uint32_t imm12 = word & 0x0FFF;
507280461Sdim  return (instr & 0xFFF0F000) | (imm4 << 16) | imm12;
508280461Sdim}
509280461Sdim
510280461Sdimuint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
511280461Sdim  // The assembler often adds one to the address of a thumb function.
512280461Sdim  // We need to undo that so it does not look like an addend.
513280461Sdim  if (value & 1) {
514280461Sdim    if (isa<DefinedAtom>(target)) {
515280461Sdim      const MachODefinedAtom *machoTarget =
516280461Sdim          reinterpret_cast<const MachODefinedAtom *>(target);
517280461Sdim      if (machoTarget->isThumb())
518280461Sdim        value &= -2; // mask off thumb-bit
519280461Sdim    }
520280461Sdim  }
521280461Sdim  return value;
522280461Sdim}
523280461Sdim
524303239Sdimllvm::Error ArchHandler_arm::getReferenceInfo(
525280461Sdim    const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
526280461Sdim    uint64_t fixupAddress, bool isBig,
527280461Sdim    FindAtomBySectionAndAddress atomFromAddress,
528280461Sdim    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
529280461Sdim    const lld::Atom **target, Reference::Addend *addend) {
530280461Sdim  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
531280461Sdim  uint64_t targetAddress;
532280461Sdim  uint32_t instruction = *(const ulittle32_t *)fixupContent;
533280461Sdim  int32_t displacement;
534280461Sdim  switch (relocPattern(reloc)) {
535280461Sdim  case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
536280461Sdim    // ex: bl _foo (and _foo is undefined)
537280461Sdim    if ((instruction & 0xD000F800) == 0x9000F000)
538280461Sdim      *kind = thumb_b22;
539280461Sdim    else
540280461Sdim      *kind = thumb_bl22;
541303239Sdim    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
542280461Sdim      return ec;
543280461Sdim    // Instruction contains branch to addend.
544280461Sdim    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
545280461Sdim    *addend = fixupAddress + 4 + displacement;
546314564Sdim    return llvm::Error::success();
547280461Sdim  case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
548280461Sdim    // ex: bl _foo (and _foo is defined)
549280461Sdim    if ((instruction & 0xD000F800) == 0x9000F000)
550280461Sdim      *kind = thumb_b22;
551280461Sdim    else
552280461Sdim      *kind = thumb_bl22;
553280461Sdim    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
554280461Sdim    targetAddress = fixupAddress + 4 + displacement;
555280461Sdim    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
556280461Sdim  case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
557280461Sdim    // ex: bl _foo+4 (and _foo is defined)
558280461Sdim    if ((instruction & 0xD000F800) == 0x9000F000)
559280461Sdim      *kind = thumb_b22;
560280461Sdim    else
561280461Sdim      *kind = thumb_bl22;
562280461Sdim    displacement = getDisplacementFromThumbBranch(instruction, fixupAddress);
563280461Sdim    targetAddress = fixupAddress + 4 + displacement;
564303239Sdim    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
565280461Sdim      return ec;
566280461Sdim    // reloc.value is target atom's address.  Instruction contains branch
567280461Sdim    // to atom+addend.
568280461Sdim    *addend += (targetAddress - reloc.value);
569314564Sdim    return llvm::Error::success();
570280461Sdim  case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
571280461Sdim    // ex: bl _foo (and _foo is undefined)
572280461Sdim    if (((instruction & 0x0F000000) == 0x0A000000)
573280461Sdim        && ((instruction & 0xF0000000) != 0xF0000000))
574280461Sdim      *kind = arm_b24;
575280461Sdim    else
576280461Sdim      *kind = arm_bl24;
577303239Sdim    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
578280461Sdim      return ec;
579280461Sdim    // Instruction contains branch to addend.
580280461Sdim    displacement = getDisplacementFromArmBranch(instruction);
581280461Sdim    *addend = fixupAddress + 8 + displacement;
582314564Sdim    return llvm::Error::success();
583280461Sdim  case ARM_RELOC_BR24 | rPcRel | rLength4:
584280461Sdim    // ex: bl _foo (and _foo is defined)
585280461Sdim    if (((instruction & 0x0F000000) == 0x0A000000)
586280461Sdim        && ((instruction & 0xF0000000) != 0xF0000000))
587280461Sdim      *kind = arm_b24;
588280461Sdim    else
589280461Sdim      *kind = arm_bl24;
590280461Sdim    displacement = getDisplacementFromArmBranch(instruction);
591280461Sdim    targetAddress = fixupAddress + 8 + displacement;
592280461Sdim    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
593280461Sdim  case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
594280461Sdim    // ex: bl _foo+4 (and _foo is defined)
595280461Sdim    if (((instruction & 0x0F000000) == 0x0A000000)
596280461Sdim        && ((instruction & 0xF0000000) != 0xF0000000))
597280461Sdim      *kind = arm_b24;
598280461Sdim    else
599280461Sdim      *kind = arm_bl24;
600280461Sdim    displacement = getDisplacementFromArmBranch(instruction);
601280461Sdim    targetAddress = fixupAddress + 8 + displacement;
602303239Sdim    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
603280461Sdim      return ec;
604280461Sdim    // reloc.value is target atom's address.  Instruction contains branch
605280461Sdim    // to atom+addend.
606280461Sdim    *addend += (targetAddress - reloc.value);
607314564Sdim    return llvm::Error::success();
608280461Sdim  case ARM_RELOC_VANILLA | rExtern | rLength4:
609280461Sdim    // ex: .long _foo (and _foo is undefined)
610280461Sdim    *kind = pointer32;
611303239Sdim    if (auto ec = atomFromSymbolIndex(reloc.symbol, target))
612280461Sdim      return ec;
613280461Sdim    *addend = instruction;
614314564Sdim    return llvm::Error::success();
615280461Sdim  case ARM_RELOC_VANILLA | rLength4:
616280461Sdim    // ex: .long _foo (and _foo is defined)
617280461Sdim    *kind = pointer32;
618303239Sdim    if (auto ec = atomFromAddress(reloc.symbol, instruction, target, addend))
619280461Sdim      return ec;
620280461Sdim    *addend = clearThumbBit((uint32_t) * addend, *target);
621314564Sdim    return llvm::Error::success();
622280461Sdim  case ARM_RELOC_VANILLA | rScattered | rLength4:
623280461Sdim    // ex: .long _foo+a (and _foo is defined)
624280461Sdim    *kind = pointer32;
625303239Sdim    if (auto ec = atomFromAddress(0, reloc.value, target, addend))
626280461Sdim      return ec;
627280461Sdim    *addend += (clearThumbBit(instruction, *target) - reloc.value);
628314564Sdim    return llvm::Error::success();
629280461Sdim  default:
630303239Sdim    return llvm::make_error<GenericError>("unsupported arm relocation type");
631280461Sdim  }
632314564Sdim  return llvm::Error::success();
633280461Sdim}
634280461Sdim
635303239Sdimllvm::Error
636280461SdimArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
637280461Sdim                                     const normalized::Relocation &reloc2,
638280461Sdim                                     const DefinedAtom *inAtom,
639280461Sdim                                     uint32_t offsetInAtom,
640280461Sdim                                     uint64_t fixupAddress, bool isBig,
641280461Sdim                                     bool scatterable,
642280461Sdim                                     FindAtomBySectionAndAddress atomFromAddr,
643280461Sdim                                     FindAtomBySymbolIndex atomFromSymbolIndex,
644280461Sdim                                     Reference::KindValue *kind,
645280461Sdim                                     const lld::Atom **target,
646280461Sdim                                     Reference::Addend *addend) {
647280461Sdim  bool pointerDiff = false;
648280461Sdim  bool funcRel;
649280461Sdim  bool top;
650280461Sdim  bool thumbReloc;
651280461Sdim  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
652280461Sdim  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenThmbLo) << 16 |
653280461Sdim         ARM_RELOC_PAIR           | rScattered | rLenThmbLo):
654280461Sdim    // ex: movw	r1, :lower16:(_x-L1) [thumb mode]
655280461Sdim    *kind = thumb_movw_funcRel;
656280461Sdim    funcRel = true;
657280461Sdim    top = false;
658280461Sdim    thumbReloc = true;
659280461Sdim    break;
660280461Sdim  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenThmbHi) << 16 |
661280461Sdim         ARM_RELOC_PAIR           | rScattered | rLenThmbHi):
662280461Sdim    // ex: movt	r1, :upper16:(_x-L1) [thumb mode]
663280461Sdim    *kind = thumb_movt_funcRel;
664280461Sdim    funcRel = true;
665280461Sdim    top = true;
666280461Sdim    thumbReloc = true;
667280461Sdim    break;
668280461Sdim  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenArmLo) << 16 |
669280461Sdim         ARM_RELOC_PAIR           | rScattered | rLenArmLo):
670280461Sdim    // ex: movw	r1, :lower16:(_x-L1) [arm mode]
671280461Sdim    *kind = arm_movw_funcRel;
672280461Sdim    funcRel = true;
673280461Sdim    top = false;
674280461Sdim    thumbReloc = false;
675280461Sdim    break;
676280461Sdim  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLenArmHi) << 16 |
677280461Sdim         ARM_RELOC_PAIR           | rScattered | rLenArmHi):
678280461Sdim    // ex: movt	r1, :upper16:(_x-L1) [arm mode]
679280461Sdim    *kind = arm_movt_funcRel;
680280461Sdim    funcRel = true;
681280461Sdim    top = true;
682280461Sdim    thumbReloc = false;
683280461Sdim    break;
684280461Sdim  case ((ARM_RELOC_HALF     | rLenThmbLo) << 16 |
685280461Sdim         ARM_RELOC_PAIR     | rLenThmbLo):
686280461Sdim    // ex: movw	r1, :lower16:_x [thumb mode]
687280461Sdim    *kind = thumb_movw;
688280461Sdim    funcRel = false;
689280461Sdim    top = false;
690280461Sdim    thumbReloc = true;
691280461Sdim    break;
692280461Sdim  case ((ARM_RELOC_HALF     | rLenThmbHi) << 16 |
693280461Sdim         ARM_RELOC_PAIR     | rLenThmbHi):
694280461Sdim    // ex: movt	r1, :upper16:_x [thumb mode]
695280461Sdim    *kind = thumb_movt;
696280461Sdim    funcRel = false;
697280461Sdim    top = true;
698280461Sdim    thumbReloc = true;
699280461Sdim    break;
700280461Sdim  case ((ARM_RELOC_HALF     | rLenArmLo) << 16 |
701280461Sdim         ARM_RELOC_PAIR     | rLenArmLo):
702280461Sdim    // ex: movw	r1, :lower16:_x [arm mode]
703280461Sdim    *kind = arm_movw;
704280461Sdim    funcRel = false;
705280461Sdim    top = false;
706280461Sdim    thumbReloc = false;
707280461Sdim    break;
708280461Sdim  case ((ARM_RELOC_HALF     | rLenArmHi) << 16 |
709280461Sdim         ARM_RELOC_PAIR     | rLenArmHi):
710280461Sdim    // ex: movt	r1, :upper16:_x [arm mode]
711280461Sdim    *kind = arm_movt;
712280461Sdim    funcRel = false;
713280461Sdim    top = true;
714280461Sdim    thumbReloc = false;
715280461Sdim    break;
716280461Sdim  case ((ARM_RELOC_HALF | rScattered  | rLenThmbLo) << 16 |
717280461Sdim         ARM_RELOC_PAIR               | rLenThmbLo):
718280461Sdim    // ex: movw	r1, :lower16:_x+a [thumb mode]
719280461Sdim    *kind = thumb_movw;
720280461Sdim    funcRel = false;
721280461Sdim    top = false;
722280461Sdim    thumbReloc = true;
723280461Sdim    break;
724280461Sdim  case ((ARM_RELOC_HALF | rScattered  | rLenThmbHi) << 16 |
725280461Sdim         ARM_RELOC_PAIR               | rLenThmbHi):
726280461Sdim    // ex: movt	r1, :upper16:_x+a [thumb mode]
727280461Sdim    *kind = thumb_movt;
728280461Sdim    funcRel = false;
729280461Sdim    top = true;
730280461Sdim    thumbReloc = true;
731280461Sdim    break;
732280461Sdim  case ((ARM_RELOC_HALF | rScattered  | rLenArmLo) << 16 |
733280461Sdim         ARM_RELOC_PAIR               | rLenArmLo):
734280461Sdim    // ex: movw	r1, :lower16:_x+a [arm mode]
735280461Sdim    *kind = arm_movw;
736280461Sdim    funcRel = false;
737280461Sdim    top = false;
738280461Sdim    thumbReloc = false;
739280461Sdim    break;
740280461Sdim  case ((ARM_RELOC_HALF | rScattered  | rLenArmHi) << 16 |
741280461Sdim         ARM_RELOC_PAIR               | rLenArmHi):
742280461Sdim    // ex: movt	r1, :upper16:_x+a [arm mode]
743280461Sdim    *kind = arm_movt;
744280461Sdim    funcRel = false;
745280461Sdim    top = true;
746280461Sdim    thumbReloc = false;
747280461Sdim    break;
748280461Sdim  case ((ARM_RELOC_HALF | rExtern   | rLenThmbLo) << 16 |
749280461Sdim         ARM_RELOC_PAIR             | rLenThmbLo):
750280461Sdim    // ex: movw	r1, :lower16:_undef [thumb mode]
751280461Sdim    *kind = thumb_movw;
752280461Sdim    funcRel = false;
753280461Sdim    top = false;
754280461Sdim    thumbReloc = true;
755280461Sdim    break;
756280461Sdim  case ((ARM_RELOC_HALF | rExtern   | rLenThmbHi) << 16 |
757280461Sdim         ARM_RELOC_PAIR             | rLenThmbHi):
758280461Sdim    // ex: movt	r1, :upper16:_undef [thumb mode]
759280461Sdim    *kind = thumb_movt;
760280461Sdim    funcRel = false;
761280461Sdim    top = true;
762280461Sdim    thumbReloc = true;
763280461Sdim    break;
764280461Sdim  case ((ARM_RELOC_HALF | rExtern   | rLenArmLo) << 16 |
765280461Sdim         ARM_RELOC_PAIR             | rLenArmLo):
766280461Sdim    // ex: movw	r1, :lower16:_undef [arm mode]
767280461Sdim    *kind = arm_movw;
768280461Sdim    funcRel = false;
769280461Sdim    top = false;
770280461Sdim    thumbReloc = false;
771280461Sdim    break;
772280461Sdim  case ((ARM_RELOC_HALF | rExtern   | rLenArmHi) << 16 |
773280461Sdim         ARM_RELOC_PAIR             | rLenArmHi):
774280461Sdim    // ex: movt	r1, :upper16:_undef [arm mode]
775280461Sdim    *kind = arm_movt;
776280461Sdim    funcRel = false;
777280461Sdim    top = true;
778280461Sdim    thumbReloc = false;
779280461Sdim    break;
780280461Sdim  case ((ARM_RELOC_SECTDIFF       | rScattered | rLength4) << 16 |
781280461Sdim         ARM_RELOC_PAIR           | rScattered | rLength4):
782280461Sdim  case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
783280461Sdim         ARM_RELOC_PAIR           | rScattered | rLength4):
784280461Sdim    // ex: .long _foo - .
785280461Sdim    pointerDiff = true;
786280461Sdim    break;
787280461Sdim  default:
788303239Sdim    return llvm::make_error<GenericError>("unsupported arm relocation pair");
789280461Sdim  }
790280461Sdim  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
791280461Sdim  uint32_t instruction = *(const ulittle32_t *)fixupContent;
792280461Sdim  uint32_t value;
793280461Sdim  uint32_t fromAddress;
794280461Sdim  uint32_t toAddress;
795280461Sdim  uint16_t instruction16;
796280461Sdim  uint16_t other16;
797280461Sdim  const lld::Atom *fromTarget;
798280461Sdim  Reference::Addend offsetInTo;
799280461Sdim  Reference::Addend offsetInFrom;
800280461Sdim  if (pointerDiff) {
801280461Sdim    toAddress = reloc1.value;
802280461Sdim    fromAddress = reloc2.value;
803303239Sdim    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
804280461Sdim      return ec;
805303239Sdim    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
806280461Sdim      return ec;
807280461Sdim    if (scatterable && (fromTarget != inAtom))
808303239Sdim      return llvm::make_error<GenericError>(
809292934Sdim          "SECTDIFF relocation where subtrahend label is not in atom");
810280461Sdim    *kind = delta32;
811280461Sdim    value = clearThumbBit(instruction, *target);
812280461Sdim    *addend = (int32_t)(value - (toAddress - fixupAddress));
813280461Sdim  } else if (funcRel) {
814280461Sdim    toAddress = reloc1.value;
815280461Sdim    fromAddress = reloc2.value;
816303239Sdim    if (auto ec = atomFromAddr(0, toAddress, target, &offsetInTo))
817280461Sdim      return ec;
818303239Sdim    if (auto ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom))
819280461Sdim      return ec;
820280461Sdim    if (fromTarget != inAtom)
821303239Sdim      return llvm::make_error<GenericError>("ARM_RELOC_HALF_SECTDIFF relocation"
822303239Sdim                                     " where subtrahend label is not in atom");
823280461Sdim    other16 = (reloc2.offset & 0xFFFF);
824280461Sdim    if (thumbReloc) {
825280461Sdim      if (top) {
826280461Sdim        if (!isThumbMovt(instruction))
827303239Sdim          return llvm::make_error<GenericError>("expected movt instruction");
828280461Sdim      }
829280461Sdim      else {
830280461Sdim        if (!isThumbMovw(instruction))
831303239Sdim          return llvm::make_error<GenericError>("expected movw instruction");
832280461Sdim      }
833280461Sdim      instruction16 = getWordFromThumbMov(instruction);
834280461Sdim    }
835280461Sdim    else {
836280461Sdim      if (top) {
837280461Sdim        if (!isArmMovt(instruction))
838303239Sdim          return llvm::make_error<GenericError>("expected movt instruction");
839280461Sdim      }
840280461Sdim      else {
841280461Sdim        if (!isArmMovw(instruction))
842303239Sdim          return llvm::make_error<GenericError>("expected movw instruction");
843280461Sdim      }
844280461Sdim      instruction16 = getWordFromArmMov(instruction);
845280461Sdim    }
846280461Sdim    if (top)
847280461Sdim      value = (instruction16 << 16) | other16;
848280461Sdim    else
849280461Sdim      value = (other16 << 16) | instruction16;
850280461Sdim    value = clearThumbBit(value, *target);
851280461Sdim    int64_t ta = (int64_t) value - (toAddress - fromAddress);
852280461Sdim    *addend = ta - offsetInFrom;
853314564Sdim    return llvm::Error::success();
854280461Sdim  } else {
855280461Sdim    uint32_t sectIndex;
856280461Sdim    if (thumbReloc) {
857280461Sdim      if (top) {
858280461Sdim        if (!isThumbMovt(instruction))
859303239Sdim          return llvm::make_error<GenericError>("expected movt instruction");
860280461Sdim      }
861280461Sdim      else {
862280461Sdim        if (!isThumbMovw(instruction))
863303239Sdim          return llvm::make_error<GenericError>("expected movw instruction");
864280461Sdim      }
865280461Sdim      instruction16 = getWordFromThumbMov(instruction);
866280461Sdim    }
867280461Sdim    else {
868280461Sdim      if (top) {
869280461Sdim        if (!isArmMovt(instruction))
870303239Sdim          return llvm::make_error<GenericError>("expected movt instruction");
871280461Sdim      }
872280461Sdim      else {
873280461Sdim        if (!isArmMovw(instruction))
874303239Sdim          return llvm::make_error<GenericError>("expected movw instruction");
875280461Sdim      }
876280461Sdim      instruction16 = getWordFromArmMov(instruction);
877280461Sdim    }
878280461Sdim    other16 = (reloc2.offset & 0xFFFF);
879280461Sdim    if (top)
880280461Sdim      value = (instruction16 << 16) | other16;
881280461Sdim    else
882280461Sdim      value = (other16 << 16) | instruction16;
883280461Sdim    if (reloc1.isExtern) {
884303239Sdim      if (auto ec = atomFromSymbolIndex(reloc1.symbol, target))
885280461Sdim        return ec;
886280461Sdim      *addend = value;
887280461Sdim    } else {
888280461Sdim      if (reloc1.scattered) {
889280461Sdim        toAddress = reloc1.value;
890280461Sdim        sectIndex = 0;
891280461Sdim      } else {
892280461Sdim        toAddress = value;
893280461Sdim        sectIndex = reloc1.symbol;
894280461Sdim      }
895303239Sdim      if (auto ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo))
896280461Sdim        return ec;
897280461Sdim      *addend = value - toAddress;
898280461Sdim    }
899280461Sdim  }
900280461Sdim
901314564Sdim  return llvm::Error::success();
902280461Sdim}
903280461Sdim
904280461Sdimvoid ArchHandler_arm::applyFixupFinal(const Reference &ref, uint8_t *loc,
905280461Sdim                                      uint64_t fixupAddress,
906280461Sdim                                      uint64_t targetAddress,
907280461Sdim                                      uint64_t inAtomAddress,
908280461Sdim                                      bool &thumbMode, bool targetIsThumb) {
909280461Sdim  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
910280461Sdim    return;
911280461Sdim  assert(ref.kindArch() == Reference::KindArch::ARM);
912280461Sdim  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
913280461Sdim  int32_t displacement;
914280461Sdim  uint16_t value16;
915280461Sdim  uint32_t value32;
916280461Sdim  switch (static_cast<ArmKind>(ref.kindValue())) {
917280461Sdim  case modeThumbCode:
918280461Sdim    thumbMode = true;
919280461Sdim    break;
920280461Sdim  case modeArmCode:
921280461Sdim    thumbMode = false;
922280461Sdim    break;
923280461Sdim  case modeData:
924280461Sdim    break;
925280461Sdim  case thumb_b22:
926280461Sdim  case thumb_bl22:
927280461Sdim    assert(thumbMode);
928280461Sdim    displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
929280461Sdim    value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
930280461Sdim                                           displacement, targetIsThumb);
931280461Sdim    *loc32 = value32;
932280461Sdim    break;
933280461Sdim  case thumb_movw:
934280461Sdim    assert(thumbMode);
935280461Sdim    value16 = (targetAddress + ref.addend()) & 0xFFFF;
936280461Sdim    if (targetIsThumb)
937280461Sdim      value16 |= 1;
938280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
939280461Sdim    break;
940280461Sdim  case thumb_movt:
941280461Sdim    assert(thumbMode);
942280461Sdim    value16 = (targetAddress + ref.addend()) >> 16;
943280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
944280461Sdim    break;
945280461Sdim  case thumb_movw_funcRel:
946280461Sdim    assert(thumbMode);
947280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
948280461Sdim    if (targetIsThumb)
949280461Sdim      value16 |= 1;
950280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
951280461Sdim    break;
952280461Sdim  case thumb_movt_funcRel:
953280461Sdim    assert(thumbMode);
954280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
955280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
956280461Sdim    break;
957280461Sdim  case arm_b24:
958280461Sdim  case arm_bl24:
959280461Sdim   assert(!thumbMode);
960280461Sdim    displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
961280461Sdim    value32 = setDisplacementInArmBranch(*loc32, displacement, targetIsThumb);
962280461Sdim    *loc32 = value32;
963280461Sdim    break;
964280461Sdim  case arm_movw:
965280461Sdim    assert(!thumbMode);
966280461Sdim    value16 = (targetAddress + ref.addend()) & 0xFFFF;
967280461Sdim    if (targetIsThumb)
968280461Sdim      value16 |= 1;
969280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
970280461Sdim    break;
971280461Sdim  case arm_movt:
972280461Sdim    assert(!thumbMode);
973280461Sdim    value16 = (targetAddress + ref.addend()) >> 16;
974280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
975280461Sdim    break;
976280461Sdim  case arm_movw_funcRel:
977280461Sdim    assert(!thumbMode);
978280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
979280461Sdim    if (targetIsThumb)
980280461Sdim      value16 |= 1;
981280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
982280461Sdim    break;
983280461Sdim  case arm_movt_funcRel:
984280461Sdim    assert(!thumbMode);
985280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
986280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
987280461Sdim    break;
988280461Sdim  case pointer32:
989280461Sdim    if (targetIsThumb)
990280461Sdim      *loc32 = targetAddress + ref.addend() + 1;
991280461Sdim    else
992280461Sdim      *loc32 = targetAddress + ref.addend();
993280461Sdim    break;
994280461Sdim  case delta32:
995280461Sdim    if (targetIsThumb)
996280461Sdim      *loc32 = targetAddress - fixupAddress + ref.addend() + 1;
997280461Sdim    else
998280461Sdim      *loc32 = targetAddress - fixupAddress + ref.addend();
999280461Sdim    break;
1000280461Sdim  case lazyPointer:
1001280461Sdim    // do nothing
1002280461Sdim    break;
1003280461Sdim  case lazyImmediateLocation:
1004280461Sdim    *loc32 = ref.addend();
1005280461Sdim    break;
1006280461Sdim  case invalid:
1007280461Sdim    llvm_unreachable("invalid ARM Reference Kind");
1008280461Sdim    break;
1009280461Sdim  }
1010280461Sdim}
1011280461Sdim
1012280461Sdimvoid ArchHandler_arm::generateAtomContent(const DefinedAtom &atom,
1013280461Sdim                                          bool relocatable,
1014280461Sdim                                          FindAddressForAtom findAddress,
1015280461Sdim                                          FindAddressForAtom findSectionAddress,
1016280461Sdim                                          uint64_t imageBaseAddress,
1017303239Sdim                            llvm::MutableArrayRef<uint8_t> atomContentBuffer) {
1018280461Sdim  // Copy raw bytes.
1019303239Sdim  std::copy(atom.rawContent().begin(), atom.rawContent().end(),
1020303239Sdim            atomContentBuffer.begin());
1021280461Sdim  // Apply fix-ups.
1022280461Sdim  bool thumbMode = false;
1023280461Sdim  for (const Reference *ref : atom) {
1024280461Sdim    uint32_t offset = ref->offsetInAtom();
1025280461Sdim    const Atom *target = ref->target();
1026280461Sdim    uint64_t targetAddress = 0;
1027280461Sdim    bool targetIsThumb = false;
1028280461Sdim    if (const DefinedAtom *defTarg = dyn_cast<DefinedAtom>(target)) {
1029280461Sdim      targetAddress = findAddress(*target);
1030280461Sdim      targetIsThumb = isThumbFunction(*defTarg);
1031280461Sdim    }
1032280461Sdim    uint64_t atomAddress = findAddress(atom);
1033280461Sdim    uint64_t fixupAddress = atomAddress + offset;
1034280461Sdim    if (relocatable) {
1035280461Sdim      applyFixupRelocatable(*ref, &atomContentBuffer[offset], fixupAddress,
1036280461Sdim                            targetAddress, atomAddress, thumbMode,
1037280461Sdim                            targetIsThumb);
1038280461Sdim    } else {
1039280461Sdim      applyFixupFinal(*ref, &atomContentBuffer[offset], fixupAddress,
1040280461Sdim                      targetAddress, atomAddress, thumbMode, targetIsThumb);
1041280461Sdim    }
1042280461Sdim  }
1043280461Sdim}
1044280461Sdim
1045280461Sdimbool ArchHandler_arm::useExternalRelocationTo(const Atom &target) {
1046280461Sdim  // Undefined symbols are referenced via external relocations.
1047280461Sdim  if (isa<UndefinedAtom>(&target))
1048280461Sdim    return true;
1049280461Sdim  if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&target)) {
1050280461Sdim     switch (defAtom->merge()) {
1051280461Sdim     case DefinedAtom::mergeAsTentative:
1052280461Sdim       // Tentative definitions are referenced via external relocations.
1053280461Sdim       return true;
1054280461Sdim     case DefinedAtom::mergeAsWeak:
1055280461Sdim     case DefinedAtom::mergeAsWeakAndAddressUsed:
1056280461Sdim       // Global weak-defs are referenced via external relocations.
1057280461Sdim       return (defAtom->scope() == DefinedAtom::scopeGlobal);
1058280461Sdim     default:
1059280461Sdim       break;
1060280461Sdim    }
1061280461Sdim  }
1062280461Sdim  // Everything else is reference via an internal relocation.
1063280461Sdim  return false;
1064280461Sdim}
1065280461Sdim
1066280461Sdimvoid ArchHandler_arm::applyFixupRelocatable(const Reference &ref, uint8_t *loc,
1067280461Sdim                                            uint64_t fixupAddress,
1068280461Sdim                                            uint64_t targetAddress,
1069280461Sdim                                            uint64_t inAtomAddress,
1070280461Sdim                                            bool &thumbMode,
1071280461Sdim                                            bool targetIsThumb) {
1072280461Sdim  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
1073280461Sdim    return;
1074280461Sdim  assert(ref.kindArch() == Reference::KindArch::ARM);
1075280461Sdim  bool useExternalReloc = useExternalRelocationTo(*ref.target());
1076280461Sdim  ulittle32_t *loc32 = reinterpret_cast<ulittle32_t *>(loc);
1077280461Sdim  int32_t displacement;
1078280461Sdim  uint16_t value16;
1079280461Sdim  uint32_t value32;
1080280461Sdim  bool targetIsUndef = isa<UndefinedAtom>(ref.target());
1081280461Sdim  switch (static_cast<ArmKind>(ref.kindValue())) {
1082280461Sdim  case modeThumbCode:
1083280461Sdim    thumbMode = true;
1084280461Sdim    break;
1085280461Sdim  case modeArmCode:
1086280461Sdim    thumbMode = false;
1087280461Sdim    break;
1088280461Sdim  case modeData:
1089280461Sdim    break;
1090280461Sdim  case thumb_b22:
1091280461Sdim  case thumb_bl22:
1092280461Sdim    assert(thumbMode);
1093280461Sdim    if (useExternalReloc)
1094280461Sdim      displacement = (ref.addend() - (fixupAddress + 4));
1095280461Sdim    else
1096280461Sdim      displacement = (targetAddress - (fixupAddress + 4)) + ref.addend();
1097280461Sdim    value32 = setDisplacementInThumbBranch(*loc32, fixupAddress,
1098280461Sdim                                           displacement,
1099280461Sdim                                           targetIsUndef || targetIsThumb);
1100280461Sdim    *loc32 = value32;
1101280461Sdim    break;
1102280461Sdim  case thumb_movw:
1103280461Sdim    assert(thumbMode);
1104280461Sdim    if (useExternalReloc)
1105280461Sdim      value16 = ref.addend() & 0xFFFF;
1106280461Sdim    else
1107280461Sdim      value16 = (targetAddress + ref.addend()) & 0xFFFF;
1108280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
1109280461Sdim    break;
1110280461Sdim  case thumb_movt:
1111280461Sdim    assert(thumbMode);
1112280461Sdim    if (useExternalReloc)
1113280461Sdim      value16 = ref.addend() >> 16;
1114280461Sdim    else
1115280461Sdim      value16 = (targetAddress + ref.addend()) >> 16;
1116280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
1117280461Sdim    break;
1118280461Sdim  case thumb_movw_funcRel:
1119280461Sdim    assert(thumbMode);
1120280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
1121280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
1122280461Sdim    break;
1123280461Sdim  case thumb_movt_funcRel:
1124280461Sdim    assert(thumbMode);
1125280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
1126280461Sdim    *loc32 = setWordFromThumbMov(*loc32, value16);
1127280461Sdim    break;
1128280461Sdim  case arm_b24:
1129280461Sdim  case arm_bl24:
1130280461Sdim    assert(!thumbMode);
1131280461Sdim    if (useExternalReloc)
1132280461Sdim      displacement = (ref.addend() - (fixupAddress + 8));
1133280461Sdim    else
1134280461Sdim      displacement = (targetAddress - (fixupAddress + 8)) + ref.addend();
1135280461Sdim    value32 = setDisplacementInArmBranch(*loc32, displacement,
1136280461Sdim                                         targetIsThumb);
1137280461Sdim    *loc32 = value32;
1138280461Sdim    break;
1139280461Sdim  case arm_movw:
1140280461Sdim    assert(!thumbMode);
1141280461Sdim    if (useExternalReloc)
1142280461Sdim      value16 = ref.addend() & 0xFFFF;
1143280461Sdim    else
1144280461Sdim      value16 = (targetAddress + ref.addend()) & 0xFFFF;
1145280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
1146280461Sdim    break;
1147280461Sdim  case arm_movt:
1148280461Sdim    assert(!thumbMode);
1149280461Sdim    if (useExternalReloc)
1150280461Sdim      value16 = ref.addend() >> 16;
1151280461Sdim    else
1152280461Sdim      value16 = (targetAddress + ref.addend()) >> 16;
1153280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
1154280461Sdim    break;
1155280461Sdim  case arm_movw_funcRel:
1156280461Sdim    assert(!thumbMode);
1157280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) & 0xFFFF;
1158280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
1159280461Sdim    break;
1160280461Sdim  case arm_movt_funcRel:
1161280461Sdim    assert(!thumbMode);
1162280461Sdim    value16 = (targetAddress - inAtomAddress + ref.addend()) >> 16;
1163280461Sdim    *loc32 = setWordFromArmMov(*loc32, value16);
1164280461Sdim    break;
1165280461Sdim  case pointer32:
1166280461Sdim    *loc32 = targetAddress + ref.addend();
1167280461Sdim    break;
1168280461Sdim  case delta32:
1169280461Sdim    *loc32 = targetAddress - fixupAddress + ref.addend();
1170280461Sdim    break;
1171280461Sdim  case lazyPointer:
1172280461Sdim  case lazyImmediateLocation:
1173280461Sdim    // do nothing
1174280461Sdim    break;
1175280461Sdim  case invalid:
1176280461Sdim    llvm_unreachable("invalid ARM Reference Kind");
1177280461Sdim    break;
1178280461Sdim  }
1179280461Sdim}
1180280461Sdim
1181280461Sdimvoid ArchHandler_arm::appendSectionRelocations(
1182280461Sdim                                   const DefinedAtom &atom,
1183280461Sdim                                   uint64_t atomSectionOffset,
1184280461Sdim                                   const Reference &ref,
1185280461Sdim                                   FindSymbolIndexForAtom symbolIndexForAtom,
1186280461Sdim                                   FindSectionIndexForAtom sectionIndexForAtom,
1187280461Sdim                                   FindAddressForAtom addressForAtom,
1188280461Sdim                                   normalized::Relocations &relocs) {
1189280461Sdim  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
1190280461Sdim    return;
1191280461Sdim  assert(ref.kindArch() == Reference::KindArch::ARM);
1192280461Sdim  uint32_t sectionOffset = atomSectionOffset + ref.offsetInAtom();
1193280461Sdim  bool useExternalReloc = useExternalRelocationTo(*ref.target());
1194280461Sdim  uint32_t targetAtomAddress;
1195280461Sdim  uint32_t fromAtomAddress;
1196280461Sdim  uint16_t other16;
1197280461Sdim  switch (static_cast<ArmKind>(ref.kindValue())) {
1198280461Sdim  case modeThumbCode:
1199280461Sdim  case modeArmCode:
1200280461Sdim  case modeData:
1201280461Sdim    // Do nothing.
1202280461Sdim    break;
1203280461Sdim  case thumb_b22:
1204280461Sdim  case thumb_bl22:
1205280461Sdim    if (useExternalReloc) {
1206280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1207280461Sdim                  ARM_THUMB_RELOC_BR22 | rExtern    | rPcRel | rLength4);
1208280461Sdim    } else {
1209280461Sdim      if (ref.addend() != 0)
1210280461Sdim        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1211280461Sdim                  ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4);
1212280461Sdim      else
1213280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1214280461Sdim                  ARM_THUMB_RELOC_BR22 |              rPcRel | rLength4);
1215280461Sdim    }
1216280461Sdim    break;
1217280461Sdim  case thumb_movw:
1218280461Sdim    if (useExternalReloc) {
1219280461Sdim      other16 = ref.addend() >> 16;
1220280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1221280461Sdim                  ARM_RELOC_HALF | rExtern    | rLenThmbLo);
1222280461Sdim      appendReloc(relocs, other16, 0, 0,
1223280461Sdim                  ARM_RELOC_PAIR              | rLenThmbLo);
1224280461Sdim    } else {
1225280461Sdim      targetAtomAddress = addressForAtom(*ref.target());
1226280461Sdim      if (ref.addend() != 0) {
1227280461Sdim        other16 = (targetAtomAddress + ref.addend()) >> 16;
1228280461Sdim        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1229280461Sdim                  ARM_RELOC_HALF | rScattered | rLenThmbLo);
1230280461Sdim        appendReloc(relocs, other16, 0, 0,
1231280461Sdim                  ARM_RELOC_PAIR              | rLenThmbLo);
1232280461Sdim      } else {
1233280461Sdim        other16 = (targetAtomAddress + ref.addend()) >> 16;
1234280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1235280461Sdim                  ARM_RELOC_HALF              | rLenThmbLo);
1236280461Sdim        appendReloc(relocs, other16, 0, 0,
1237280461Sdim                  ARM_RELOC_PAIR              | rLenThmbLo);
1238280461Sdim      }
1239280461Sdim    }
1240280461Sdim    break;
1241280461Sdim  case thumb_movt:
1242280461Sdim    if (useExternalReloc) {
1243280461Sdim      other16 = ref.addend() & 0xFFFF;
1244280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1245280461Sdim                  ARM_RELOC_HALF | rExtern    | rLenThmbHi);
1246280461Sdim      appendReloc(relocs, other16, 0, 0,
1247280461Sdim                  ARM_RELOC_PAIR              | rLenThmbHi);
1248280461Sdim    } else {
1249280461Sdim      targetAtomAddress = addressForAtom(*ref.target());
1250280461Sdim      if (ref.addend() != 0) {
1251280461Sdim        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1252280461Sdim        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1253280461Sdim                    ARM_RELOC_HALF | rScattered | rLenThmbHi);
1254280461Sdim        appendReloc(relocs, other16, 0, 0,
1255280461Sdim                    ARM_RELOC_PAIR              | rLenThmbHi);
1256280461Sdim      } else {
1257280461Sdim        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1258280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1259280461Sdim                    ARM_RELOC_HALF              | rLenThmbHi);
1260280461Sdim        appendReloc(relocs, other16, 0, 0,
1261280461Sdim                    ARM_RELOC_PAIR              | rLenThmbHi);
1262280461Sdim      }
1263280461Sdim    }
1264280461Sdim    break;
1265280461Sdim  case thumb_movw_funcRel:
1266280461Sdim    fromAtomAddress = addressForAtom(atom);
1267280461Sdim    targetAtomAddress = addressForAtom(*ref.target());
1268280461Sdim    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
1269280461Sdim    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1270280461Sdim                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbLo);
1271280461Sdim    appendReloc(relocs, other16, 0, fromAtomAddress,
1272280461Sdim                ARM_RELOC_PAIR          | rScattered | rLenThmbLo);
1273280461Sdim    break;
1274280461Sdim  case thumb_movt_funcRel:
1275280461Sdim    fromAtomAddress = addressForAtom(atom);
1276280461Sdim    targetAtomAddress = addressForAtom(*ref.target());
1277280461Sdim    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
1278280461Sdim    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1279280461Sdim                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenThmbHi);
1280280461Sdim    appendReloc(relocs, other16, 0, fromAtomAddress,
1281280461Sdim                ARM_RELOC_PAIR          | rScattered | rLenThmbHi);
1282280461Sdim    break;
1283280461Sdim  case arm_b24:
1284280461Sdim  case arm_bl24:
1285280461Sdim    if (useExternalReloc) {
1286280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1287280461Sdim                  ARM_RELOC_BR24 | rExtern    | rPcRel | rLength4);
1288280461Sdim    } else {
1289280461Sdim      if (ref.addend() != 0)
1290280461Sdim        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1291280461Sdim                  ARM_RELOC_BR24 | rScattered | rPcRel | rLength4);
1292280461Sdim      else
1293280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1294280461Sdim                  ARM_RELOC_BR24 |              rPcRel | rLength4);
1295280461Sdim    }
1296280461Sdim    break;
1297280461Sdim  case arm_movw:
1298280461Sdim    if (useExternalReloc) {
1299280461Sdim      other16 = ref.addend() >> 16;
1300280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1301280461Sdim                  ARM_RELOC_HALF | rExtern    | rLenArmLo);
1302280461Sdim      appendReloc(relocs, other16, 0, 0,
1303280461Sdim                  ARM_RELOC_PAIR              | rLenArmLo);
1304280461Sdim    } else {
1305280461Sdim      targetAtomAddress = addressForAtom(*ref.target());
1306280461Sdim      if (ref.addend() != 0) {
1307280461Sdim        other16 = (targetAtomAddress + ref.addend()) >> 16;
1308280461Sdim        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1309280461Sdim                  ARM_RELOC_HALF | rScattered | rLenArmLo);
1310280461Sdim        appendReloc(relocs, other16, 0, 0,
1311280461Sdim                  ARM_RELOC_PAIR              | rLenArmLo);
1312280461Sdim      } else {
1313280461Sdim        other16 = (targetAtomAddress + ref.addend()) >> 16;
1314280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1315280461Sdim                  ARM_RELOC_HALF              | rLenArmLo);
1316280461Sdim        appendReloc(relocs, other16, 0, 0,
1317280461Sdim                  ARM_RELOC_PAIR              | rLenArmLo);
1318280461Sdim      }
1319280461Sdim    }
1320280461Sdim    break;
1321280461Sdim  case arm_movt:
1322280461Sdim    if (useExternalReloc) {
1323280461Sdim      other16 = ref.addend() & 0xFFFF;
1324280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()), 0,
1325280461Sdim                  ARM_RELOC_HALF | rExtern    | rLenArmHi);
1326280461Sdim      appendReloc(relocs, other16, 0, 0,
1327280461Sdim                  ARM_RELOC_PAIR              | rLenArmHi);
1328280461Sdim    } else {
1329280461Sdim      targetAtomAddress = addressForAtom(*ref.target());
1330280461Sdim      if (ref.addend() != 0) {
1331280461Sdim        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1332280461Sdim        appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1333280461Sdim                  ARM_RELOC_HALF | rScattered | rLenArmHi);
1334280461Sdim        appendReloc(relocs, other16, 0, 0,
1335280461Sdim                  ARM_RELOC_PAIR              | rLenArmHi);
1336280461Sdim      } else {
1337280461Sdim        other16 = (targetAtomAddress + ref.addend()) & 0xFFFF;
1338280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1339280461Sdim                  ARM_RELOC_HALF              | rLenArmHi);
1340280461Sdim        appendReloc(relocs, other16, 0, 0,
1341280461Sdim                  ARM_RELOC_PAIR              | rLenArmHi);
1342280461Sdim      }
1343280461Sdim    }
1344280461Sdim    break;
1345280461Sdim  case arm_movw_funcRel:
1346280461Sdim    fromAtomAddress = addressForAtom(atom);
1347280461Sdim    targetAtomAddress = addressForAtom(*ref.target());
1348280461Sdim    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) >> 16;
1349280461Sdim    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1350280461Sdim                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmLo);
1351280461Sdim    appendReloc(relocs, other16, 0, fromAtomAddress,
1352280461Sdim                ARM_RELOC_PAIR          | rScattered | rLenArmLo);
1353280461Sdim    break;
1354280461Sdim  case arm_movt_funcRel:
1355280461Sdim    fromAtomAddress = addressForAtom(atom);
1356280461Sdim    targetAtomAddress = addressForAtom(*ref.target());
1357280461Sdim    other16 = (targetAtomAddress - fromAtomAddress + ref.addend()) & 0xFFFF;
1358280461Sdim    appendReloc(relocs, sectionOffset, 0, targetAtomAddress,
1359280461Sdim                ARM_RELOC_HALF_SECTDIFF | rScattered | rLenArmHi);
1360280461Sdim    appendReloc(relocs, other16, 0, fromAtomAddress,
1361280461Sdim                ARM_RELOC_PAIR          | rScattered | rLenArmHi);
1362280461Sdim    break;
1363280461Sdim  case pointer32:
1364280461Sdim    if (useExternalReloc) {
1365280461Sdim      appendReloc(relocs, sectionOffset, symbolIndexForAtom(*ref.target()),  0,
1366280461Sdim                ARM_RELOC_VANILLA |    rExtern     |  rLength4);
1367280461Sdim    }
1368280461Sdim    else {
1369280461Sdim      if (ref.addend() != 0)
1370280461Sdim        appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1371280461Sdim                ARM_RELOC_VANILLA |    rScattered  |  rLength4);
1372280461Sdim      else
1373280461Sdim        appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()),0,
1374280461Sdim                ARM_RELOC_VANILLA |                   rLength4);
1375280461Sdim    }
1376280461Sdim    break;
1377280461Sdim  case delta32:
1378280461Sdim    appendReloc(relocs, sectionOffset, 0, addressForAtom(*ref.target()),
1379280461Sdim              ARM_RELOC_SECTDIFF  |  rScattered    | rLength4);
1380280461Sdim    appendReloc(relocs, sectionOffset, 0, addressForAtom(atom) +
1381280461Sdim                                                           ref.offsetInAtom(),
1382280461Sdim              ARM_RELOC_PAIR      |  rScattered    | rLength4);
1383280461Sdim    break;
1384280461Sdim  case lazyPointer:
1385280461Sdim  case lazyImmediateLocation:
1386280461Sdim    // do nothing
1387280461Sdim    break;
1388280461Sdim  case invalid:
1389280461Sdim    llvm_unreachable("invalid ARM Reference Kind");
1390280461Sdim    break;
1391280461Sdim  }
1392280461Sdim}
1393280461Sdim
1394280461Sdimvoid ArchHandler_arm::addAdditionalReferences(MachODefinedAtom &atom) {
1395280461Sdim  if (atom.isThumb()) {
1396303239Sdim    atom.addReference(Reference::KindNamespace::mach_o,
1397303239Sdim                      Reference::KindArch::ARM, modeThumbCode, 0, &atom, 0);
1398280461Sdim  }
1399280461Sdim}
1400280461Sdim
1401280461Sdimbool ArchHandler_arm::isThumbFunction(const DefinedAtom &atom) {
1402280461Sdim  for (const Reference *ref : atom) {
1403280461Sdim    if (ref->offsetInAtom() != 0)
1404280461Sdim      return false;
1405280461Sdim    if (ref->kindNamespace() != Reference::KindNamespace::mach_o)
1406280461Sdim      continue;
1407280461Sdim    assert(ref->kindArch() == Reference::KindArch::ARM);
1408280461Sdim    if (ref->kindValue() == modeThumbCode)
1409280461Sdim      return true;
1410280461Sdim  }
1411280461Sdim  return false;
1412280461Sdim}
1413280461Sdim
1414280461Sdimclass Thumb2ToArmShimAtom : public SimpleDefinedAtom {
1415280461Sdimpublic:
1416280461Sdim  Thumb2ToArmShimAtom(MachOFile &file, StringRef targetName,
1417280461Sdim                      const DefinedAtom &target)
1418280461Sdim      : SimpleDefinedAtom(file) {
1419280461Sdim    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
1420280461Sdim                 ArchHandler_arm::modeThumbCode, 0, this, 0);
1421280461Sdim    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
1422280461Sdim                 ArchHandler_arm::delta32, 8, &target, 0);
1423280461Sdim    std::string name = std::string(targetName) + "$shim";
1424280461Sdim    StringRef tmp(name);
1425280461Sdim    _name = tmp.copy(file.allocator());
1426280461Sdim  }
1427280461Sdim
1428303239Sdim  ~Thumb2ToArmShimAtom() override = default;
1429303239Sdim
1430280461Sdim  StringRef name() const override {
1431280461Sdim    return _name;
1432280461Sdim  }
1433280461Sdim
1434280461Sdim  ContentType contentType() const override {
1435280461Sdim    return DefinedAtom::typeCode;
1436280461Sdim  }
1437280461Sdim
1438292934Sdim  Alignment alignment() const override { return 4; }
1439280461Sdim
1440280461Sdim  uint64_t size() const override {
1441280461Sdim    return 12;
1442280461Sdim  }
1443280461Sdim
1444280461Sdim  ContentPermissions permissions() const override {
1445280461Sdim    return DefinedAtom::permR_X;
1446280461Sdim  }
1447280461Sdim
1448280461Sdim  ArrayRef<uint8_t> rawContent() const override {
1449280461Sdim    static const uint8_t bytes[] =
1450280461Sdim    { 0xDF, 0xF8, 0x04, 0xC0,       //  ldr ip, pc + 4
1451280461Sdim      0xFF, 0x44,                   //  add ip, pc, ip
1452280461Sdim      0x60, 0x47,                   //  ldr pc, [ip]
1453280461Sdim      0x00, 0x00, 0x00, 0x00 };     //  .long target - this
1454280461Sdim    assert(sizeof(bytes) == size());
1455280461Sdim    return llvm::makeArrayRef(bytes, sizeof(bytes));
1456280461Sdim  }
1457280461Sdimprivate:
1458280461Sdim  StringRef _name;
1459280461Sdim};
1460280461Sdim
1461280461Sdimclass ArmToThumbShimAtom : public SimpleDefinedAtom {
1462280461Sdimpublic:
1463280461Sdim  ArmToThumbShimAtom(MachOFile &file, StringRef targetName,
1464280461Sdim                     const DefinedAtom &target)
1465280461Sdim      : SimpleDefinedAtom(file) {
1466280461Sdim    addReference(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
1467280461Sdim                 ArchHandler_arm::delta32, 12, &target, 0);
1468280461Sdim    std::string name = std::string(targetName) + "$shim";
1469280461Sdim    StringRef tmp(name);
1470280461Sdim    _name = tmp.copy(file.allocator());
1471280461Sdim  }
1472280461Sdim
1473303239Sdim  ~ArmToThumbShimAtom() override = default;
1474303239Sdim
1475280461Sdim  StringRef name() const override {
1476280461Sdim    return _name;
1477280461Sdim  }
1478280461Sdim
1479280461Sdim  ContentType contentType() const override {
1480280461Sdim    return DefinedAtom::typeCode;
1481280461Sdim  }
1482280461Sdim
1483292934Sdim  Alignment alignment() const override { return 4; }
1484280461Sdim
1485280461Sdim  uint64_t size() const override {
1486280461Sdim    return 16;
1487280461Sdim  }
1488280461Sdim
1489280461Sdim  ContentPermissions permissions() const override {
1490280461Sdim    return DefinedAtom::permR_X;
1491280461Sdim  }
1492280461Sdim
1493280461Sdim  ArrayRef<uint8_t> rawContent() const override {
1494280461Sdim    static const uint8_t bytes[] =
1495280461Sdim    { 0x04, 0xC0, 0x9F, 0xE5,       //  ldr ip, pc + 4
1496280461Sdim      0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
1497280461Sdim      0x1C, 0xFF, 0x2F, 0xE1,       //  ldr pc, [ip]
1498280461Sdim      0x00, 0x00, 0x00, 0x00 };     //  .long target - this
1499280461Sdim    assert(sizeof(bytes) == size());
1500280461Sdim    return llvm::makeArrayRef(bytes, sizeof(bytes));
1501280461Sdim  }
1502280461Sdimprivate:
1503280461Sdim  StringRef _name;
1504280461Sdim};
1505280461Sdim
1506280461Sdimconst DefinedAtom *ArchHandler_arm::createShim(MachOFile &file,
1507280461Sdim                                               bool thumbToArm,
1508280461Sdim                                               const DefinedAtom &target) {
1509280461Sdim  bool isStub = (target.contentType() == DefinedAtom::typeStub);
1510280461Sdim  StringRef targetName = isStub ? stubName(target) : target.name();
1511280461Sdim  if (thumbToArm)
1512280461Sdim    return new (file.allocator()) Thumb2ToArmShimAtom(file, targetName, target);
1513280461Sdim  else
1514280461Sdim    return new (file.allocator()) ArmToThumbShimAtom(file, targetName, target);
1515280461Sdim}
1516280461Sdim
1517280461Sdimstd::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
1518280461Sdim  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
1519280461Sdim}
1520280461Sdim
1521280461Sdim} // namespace mach_o
1522280461Sdim} // namespace lld
1523