1226584Sdim//===-- ARMAsmBackend.cpp - ARM Assembler Backend -------------------------===//
2226584Sdim//
3226584Sdim//                     The LLVM Compiler Infrastructure
4226584Sdim//
5226584Sdim// This file is distributed under the University of Illinois Open Source
6226584Sdim// License. See LICENSE.TXT for details.
7226584Sdim//
8226584Sdim//===----------------------------------------------------------------------===//
9226584Sdim
10226584Sdim#include "MCTargetDesc/ARMMCTargetDesc.h"
11252723Sdim#include "MCTargetDesc/ARMAddressingModes.h"
12226584Sdim#include "MCTargetDesc/ARMBaseInfo.h"
13226584Sdim#include "MCTargetDesc/ARMFixupKinds.h"
14252723Sdim#include "llvm/ADT/StringSwitch.h"
15252723Sdim#include "llvm/MC/MCAsmBackend.h"
16226584Sdim#include "llvm/MC/MCAssembler.h"
17245431Sdim#include "llvm/MC/MCContext.h"
18226584Sdim#include "llvm/MC/MCDirectives.h"
19226584Sdim#include "llvm/MC/MCELFObjectWriter.h"
20226584Sdim#include "llvm/MC/MCExpr.h"
21235633Sdim#include "llvm/MC/MCFixupKindInfo.h"
22226584Sdim#include "llvm/MC/MCMachObjectWriter.h"
23226584Sdim#include "llvm/MC/MCObjectWriter.h"
24226584Sdim#include "llvm/MC/MCSectionELF.h"
25226584Sdim#include "llvm/MC/MCSectionMachO.h"
26226584Sdim#include "llvm/MC/MCSubtargetInfo.h"
27235633Sdim#include "llvm/MC/MCValue.h"
28226584Sdim#include "llvm/Support/ELF.h"
29226584Sdim#include "llvm/Support/ErrorHandling.h"
30263509Sdim#include "llvm/Support/MachO.h"
31226584Sdim#include "llvm/Support/raw_ostream.h"
32226584Sdimusing namespace llvm;
33226584Sdim
34226584Sdimnamespace {
35226584Sdimclass ARMELFObjectWriter : public MCELFObjectTargetWriter {
36226584Sdimpublic:
37235633Sdim  ARMELFObjectWriter(uint8_t OSABI)
38235633Sdim    : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, ELF::EM_ARM,
39226584Sdim                              /*HasRelocationAddend*/ false) {}
40226584Sdim};
41226584Sdim
42226584Sdimclass ARMAsmBackend : public MCAsmBackend {
43226584Sdim  const MCSubtargetInfo* STI;
44226584Sdim  bool isThumbMode;  // Currently emitting Thumb code.
45226584Sdimpublic:
46226584Sdim  ARMAsmBackend(const Target &T, const StringRef TT)
47226584Sdim    : MCAsmBackend(), STI(ARM_MC::createARMMCSubtargetInfo(TT, "", "")),
48226584Sdim      isThumbMode(TT.startswith("thumb")) {}
49226584Sdim
50226584Sdim  ~ARMAsmBackend() {
51226584Sdim    delete STI;
52226584Sdim  }
53226584Sdim
54226584Sdim  unsigned getNumFixupKinds() const { return ARM::NumTargetFixupKinds; }
55226584Sdim
56226584Sdim  bool hasNOP() const {
57226584Sdim    return (STI->getFeatureBits() & ARM::HasV6T2Ops) != 0;
58226584Sdim  }
59226584Sdim
60226584Sdim  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
61226584Sdim    const static MCFixupKindInfo Infos[ARM::NumTargetFixupKinds] = {
62226584Sdim// This table *must* be in the order that the fixup_* kinds are defined in
63226584Sdim// ARMFixupKinds.h.
64226584Sdim//
65226584Sdim// Name                      Offset (bits) Size (bits)     Flags
66235633Sdim{ "fixup_arm_ldst_pcrel_12", 0,            32,  MCFixupKindInfo::FKF_IsPCRel },
67226584Sdim{ "fixup_t2_ldst_pcrel_12",  0,            32,  MCFixupKindInfo::FKF_IsPCRel |
68226584Sdim                                   MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
69235633Sdim{ "fixup_arm_pcrel_10_unscaled", 0,        32,  MCFixupKindInfo::FKF_IsPCRel },
70235633Sdim{ "fixup_arm_pcrel_10",      0,            32,  MCFixupKindInfo::FKF_IsPCRel },
71226584Sdim{ "fixup_t2_pcrel_10",       0,            32,  MCFixupKindInfo::FKF_IsPCRel |
72226584Sdim                                   MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
73226584Sdim{ "fixup_thumb_adr_pcrel_10",0,            8,   MCFixupKindInfo::FKF_IsPCRel |
74226584Sdim                                   MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
75235633Sdim{ "fixup_arm_adr_pcrel_12",  0,            32,  MCFixupKindInfo::FKF_IsPCRel },
76226584Sdim{ "fixup_t2_adr_pcrel_12",   0,            32,  MCFixupKindInfo::FKF_IsPCRel |
77226584Sdim                                   MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
78226584Sdim{ "fixup_arm_condbranch",    0,            24,  MCFixupKindInfo::FKF_IsPCRel },
79226584Sdim{ "fixup_arm_uncondbranch",  0,            24,  MCFixupKindInfo::FKF_IsPCRel },
80226584Sdim{ "fixup_t2_condbranch",     0,            32,  MCFixupKindInfo::FKF_IsPCRel },
81226584Sdim{ "fixup_t2_uncondbranch",   0,            32,  MCFixupKindInfo::FKF_IsPCRel },
82226584Sdim{ "fixup_arm_thumb_br",      0,            16,  MCFixupKindInfo::FKF_IsPCRel },
83235633Sdim{ "fixup_arm_uncondbl",      0,            24,  MCFixupKindInfo::FKF_IsPCRel },
84235633Sdim{ "fixup_arm_condbl",        0,            24,  MCFixupKindInfo::FKF_IsPCRel },
85235633Sdim{ "fixup_arm_blx",           0,            24,  MCFixupKindInfo::FKF_IsPCRel },
86226584Sdim{ "fixup_arm_thumb_bl",      0,            32,  MCFixupKindInfo::FKF_IsPCRel },
87226584Sdim{ "fixup_arm_thumb_blx",     0,            32,  MCFixupKindInfo::FKF_IsPCRel },
88226584Sdim{ "fixup_arm_thumb_cb",      0,            16,  MCFixupKindInfo::FKF_IsPCRel },
89245431Sdim{ "fixup_arm_thumb_cp",      0,             8,  MCFixupKindInfo::FKF_IsPCRel |
90245431Sdim                                   MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
91226584Sdim{ "fixup_arm_thumb_bcc",     0,             8,  MCFixupKindInfo::FKF_IsPCRel },
92226584Sdim// movw / movt: 16-bits immediate but scattered into two chunks 0 - 12, 16 - 19.
93226584Sdim{ "fixup_arm_movt_hi16",     0,            20,  0 },
94226584Sdim{ "fixup_arm_movw_lo16",     0,            20,  0 },
95226584Sdim{ "fixup_t2_movt_hi16",      0,            20,  0 },
96226584Sdim{ "fixup_t2_movw_lo16",      0,            20,  0 },
97226584Sdim{ "fixup_arm_movt_hi16_pcrel", 0,          20,  MCFixupKindInfo::FKF_IsPCRel },
98226584Sdim{ "fixup_arm_movw_lo16_pcrel", 0,          20,  MCFixupKindInfo::FKF_IsPCRel },
99226584Sdim{ "fixup_t2_movt_hi16_pcrel", 0,           20,  MCFixupKindInfo::FKF_IsPCRel },
100226584Sdim{ "fixup_t2_movw_lo16_pcrel", 0,           20,  MCFixupKindInfo::FKF_IsPCRel },
101226584Sdim    };
102226584Sdim
103226584Sdim    if (Kind < FirstTargetFixupKind)
104226584Sdim      return MCAsmBackend::getFixupKindInfo(Kind);
105226584Sdim
106226584Sdim    assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
107226584Sdim           "Invalid kind!");
108226584Sdim    return Infos[Kind - FirstTargetFixupKind];
109226584Sdim  }
110226584Sdim
111235633Sdim  /// processFixupValue - Target hook to process the literal value of a fixup
112235633Sdim  /// if necessary.
113235633Sdim  void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
114235633Sdim                         const MCFixup &Fixup, const MCFragment *DF,
115235633Sdim                         MCValue &Target, uint64_t &Value,
116245431Sdim                         bool &IsResolved);
117226584Sdim
118252723Sdim
119252723Sdim  void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
120252723Sdim                  uint64_t Value) const;
121252723Sdim
122235633Sdim  bool mayNeedRelaxation(const MCInst &Inst) const;
123226584Sdim
124235633Sdim  bool fixupNeedsRelaxation(const MCFixup &Fixup,
125235633Sdim                            uint64_t Value,
126252723Sdim                            const MCRelaxableFragment *DF,
127235633Sdim                            const MCAsmLayout &Layout) const;
128226584Sdim
129235633Sdim  void relaxInstruction(const MCInst &Inst, MCInst &Res) const;
130235633Sdim
131235633Sdim  bool writeNopData(uint64_t Count, MCObjectWriter *OW) const;
132235633Sdim
133235633Sdim  void handleAssemblerFlag(MCAssemblerFlag Flag) {
134226584Sdim    switch (Flag) {
135226584Sdim    default: break;
136226584Sdim    case MCAF_Code16:
137226584Sdim      setIsThumb(true);
138226584Sdim      break;
139226584Sdim    case MCAF_Code32:
140226584Sdim      setIsThumb(false);
141226584Sdim      break;
142226584Sdim    }
143226584Sdim  }
144226584Sdim
145226584Sdim  unsigned getPointerSize() const { return 4; }
146226584Sdim  bool isThumb() const { return isThumbMode; }
147226584Sdim  void setIsThumb(bool it) { isThumbMode = it; }
148226584Sdim};
149226584Sdim} // end anonymous namespace
150226584Sdim
151235633Sdimstatic unsigned getRelaxedOpcode(unsigned Op) {
152235633Sdim  switch (Op) {
153235633Sdim  default: return Op;
154235633Sdim  case ARM::tBcc:       return ARM::t2Bcc;
155263509Sdim  case ARM::tLDRpci:    return ARM::t2LDRpci;
156235633Sdim  case ARM::tADR:       return ARM::t2ADR;
157235633Sdim  case ARM::tB:         return ARM::t2B;
158235633Sdim  }
159235633Sdim}
160235633Sdim
161235633Sdimbool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
162235633Sdim  if (getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode())
163235633Sdim    return true;
164226584Sdim  return false;
165226584Sdim}
166226584Sdim
167235633Sdimbool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
168235633Sdim                                         uint64_t Value,
169252723Sdim                                         const MCRelaxableFragment *DF,
170235633Sdim                                         const MCAsmLayout &Layout) const {
171235633Sdim  switch ((unsigned)Fixup.getKind()) {
172235633Sdim  case ARM::fixup_arm_thumb_br: {
173235633Sdim    // Relaxing tB to t2B. tB has a signed 12-bit displacement with the
174235633Sdim    // low bit being an implied zero. There's an implied +4 offset for the
175235633Sdim    // branch, so we adjust the other way here to determine what's
176235633Sdim    // encodable.
177235633Sdim    //
178235633Sdim    // Relax if the value is too big for a (signed) i8.
179235633Sdim    int64_t Offset = int64_t(Value) - 4;
180235633Sdim    return Offset > 2046 || Offset < -2048;
181235633Sdim  }
182235633Sdim  case ARM::fixup_arm_thumb_bcc: {
183235633Sdim    // Relaxing tBcc to t2Bcc. tBcc has a signed 9-bit displacement with the
184235633Sdim    // low bit being an implied zero. There's an implied +4 offset for the
185235633Sdim    // branch, so we adjust the other way here to determine what's
186235633Sdim    // encodable.
187235633Sdim    //
188235633Sdim    // Relax if the value is too big for a (signed) i8.
189235633Sdim    int64_t Offset = int64_t(Value) - 4;
190235633Sdim    return Offset > 254 || Offset < -256;
191235633Sdim  }
192235633Sdim  case ARM::fixup_thumb_adr_pcrel_10:
193235633Sdim  case ARM::fixup_arm_thumb_cp: {
194235633Sdim    // If the immediate is negative, greater than 1020, or not a multiple
195235633Sdim    // of four, the wide version of the instruction must be used.
196235633Sdim    int64_t Offset = int64_t(Value) - 4;
197235633Sdim    return Offset > 1020 || Offset < 0 || Offset & 3;
198235633Sdim  }
199235633Sdim  }
200235633Sdim  llvm_unreachable("Unexpected fixup kind in fixupNeedsRelaxation()!");
201226584Sdim}
202226584Sdim
203235633Sdimvoid ARMAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const {
204235633Sdim  unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode());
205235633Sdim
206235633Sdim  // Sanity check w/ diagnostic if we get here w/ a bogus instruction.
207235633Sdim  if (RelaxedOp == Inst.getOpcode()) {
208235633Sdim    SmallString<256> Tmp;
209235633Sdim    raw_svector_ostream OS(Tmp);
210235633Sdim    Inst.dump_pretty(OS);
211235633Sdim    OS << "\n";
212235633Sdim    report_fatal_error("unexpected instruction to relax: " + OS.str());
213235633Sdim  }
214235633Sdim
215235633Sdim  // The instructions we're relaxing have (so far) the same operands.
216235633Sdim  // We just need to update to the proper opcode.
217235633Sdim  Res = Inst;
218235633Sdim  Res.setOpcode(RelaxedOp);
219235633Sdim}
220235633Sdim
221235633Sdimbool ARMAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
222226584Sdim  const uint16_t Thumb1_16bitNopEncoding = 0x46c0; // using MOV r8,r8
223226584Sdim  const uint16_t Thumb2_16bitNopEncoding = 0xbf00; // NOP
224252723Sdim  const uint32_t ARMv4_NopEncoding = 0xe1a00000; // using MOV r0,r0
225235633Sdim  const uint32_t ARMv6T2_NopEncoding = 0xe320f000; // NOP
226226584Sdim  if (isThumb()) {
227226584Sdim    const uint16_t nopEncoding = hasNOP() ? Thumb2_16bitNopEncoding
228226584Sdim                                          : Thumb1_16bitNopEncoding;
229226584Sdim    uint64_t NumNops = Count / 2;
230226584Sdim    for (uint64_t i = 0; i != NumNops; ++i)
231226584Sdim      OW->Write16(nopEncoding);
232226584Sdim    if (Count & 1)
233226584Sdim      OW->Write8(0);
234226584Sdim    return true;
235226584Sdim  }
236226584Sdim  // ARM mode
237226584Sdim  const uint32_t nopEncoding = hasNOP() ? ARMv6T2_NopEncoding
238226584Sdim                                        : ARMv4_NopEncoding;
239226584Sdim  uint64_t NumNops = Count / 4;
240226584Sdim  for (uint64_t i = 0; i != NumNops; ++i)
241226584Sdim    OW->Write32(nopEncoding);
242226584Sdim  // FIXME: should this function return false when unable to write exactly
243226584Sdim  // 'Count' bytes with NOP encodings?
244226584Sdim  switch (Count % 4) {
245226584Sdim  default: break; // No leftover bytes to write
246226584Sdim  case 1: OW->Write8(0); break;
247226584Sdim  case 2: OW->Write16(0); break;
248226584Sdim  case 3: OW->Write16(0); OW->Write8(0xa0); break;
249226584Sdim  }
250226584Sdim
251226584Sdim  return true;
252226584Sdim}
253226584Sdim
254245431Sdimstatic unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
255245431Sdim                                 MCContext *Ctx = NULL) {
256245431Sdim  unsigned Kind = Fixup.getKind();
257226584Sdim  switch (Kind) {
258226584Sdim  default:
259226584Sdim    llvm_unreachable("Unknown fixup kind!");
260226584Sdim  case FK_Data_1:
261226584Sdim  case FK_Data_2:
262226584Sdim  case FK_Data_4:
263226584Sdim    return Value;
264226584Sdim  case ARM::fixup_arm_movt_hi16:
265226584Sdim    Value >>= 16;
266226584Sdim    // Fallthrough
267226584Sdim  case ARM::fixup_arm_movw_lo16:
268226584Sdim  case ARM::fixup_arm_movt_hi16_pcrel:
269226584Sdim  case ARM::fixup_arm_movw_lo16_pcrel: {
270226584Sdim    unsigned Hi4 = (Value & 0xF000) >> 12;
271226584Sdim    unsigned Lo12 = Value & 0x0FFF;
272226584Sdim    // inst{19-16} = Hi4;
273226584Sdim    // inst{11-0} = Lo12;
274226584Sdim    Value = (Hi4 << 16) | (Lo12);
275226584Sdim    return Value;
276226584Sdim  }
277226584Sdim  case ARM::fixup_t2_movt_hi16:
278226584Sdim    Value >>= 16;
279226584Sdim    // Fallthrough
280226584Sdim  case ARM::fixup_t2_movw_lo16:
281226584Sdim  case ARM::fixup_t2_movt_hi16_pcrel:  //FIXME: Shouldn't this be shifted like
282226584Sdim                                       // the other hi16 fixup?
283226584Sdim  case ARM::fixup_t2_movw_lo16_pcrel: {
284226584Sdim    unsigned Hi4 = (Value & 0xF000) >> 12;
285226584Sdim    unsigned i = (Value & 0x800) >> 11;
286226584Sdim    unsigned Mid3 = (Value & 0x700) >> 8;
287226584Sdim    unsigned Lo8 = Value & 0x0FF;
288226584Sdim    // inst{19-16} = Hi4;
289226584Sdim    // inst{26} = i;
290226584Sdim    // inst{14-12} = Mid3;
291226584Sdim    // inst{7-0} = Lo8;
292226584Sdim    Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8);
293226584Sdim    uint64_t swapped = (Value & 0xFFFF0000) >> 16;
294226584Sdim    swapped |= (Value & 0x0000FFFF) << 16;
295226584Sdim    return swapped;
296226584Sdim  }
297226584Sdim  case ARM::fixup_arm_ldst_pcrel_12:
298226584Sdim    // ARM PC-relative values are offset by 8.
299226584Sdim    Value -= 4;
300226584Sdim    // FALLTHROUGH
301226584Sdim  case ARM::fixup_t2_ldst_pcrel_12: {
302226584Sdim    // Offset by 4, adjusted by two due to the half-word ordering of thumb.
303226584Sdim    Value -= 4;
304226584Sdim    bool isAdd = true;
305226584Sdim    if ((int64_t)Value < 0) {
306226584Sdim      Value = -Value;
307226584Sdim      isAdd = false;
308226584Sdim    }
309245431Sdim    if (Ctx && Value >= 4096)
310245431Sdim      Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value");
311226584Sdim    Value |= isAdd << 23;
312226584Sdim
313226584Sdim    // Same addressing mode as fixup_arm_pcrel_10,
314226584Sdim    // but with 16-bit halfwords swapped.
315226584Sdim    if (Kind == ARM::fixup_t2_ldst_pcrel_12) {
316226584Sdim      uint64_t swapped = (Value & 0xFFFF0000) >> 16;
317226584Sdim      swapped |= (Value & 0x0000FFFF) << 16;
318226584Sdim      return swapped;
319226584Sdim    }
320226584Sdim
321226584Sdim    return Value;
322226584Sdim  }
323226584Sdim  case ARM::fixup_thumb_adr_pcrel_10:
324226584Sdim    return ((Value - 4) >> 2) & 0xff;
325226584Sdim  case ARM::fixup_arm_adr_pcrel_12: {
326226584Sdim    // ARM PC-relative values are offset by 8.
327226584Sdim    Value -= 8;
328226584Sdim    unsigned opc = 4; // bits {24-21}. Default to add: 0b0100
329226584Sdim    if ((int64_t)Value < 0) {
330226584Sdim      Value = -Value;
331226584Sdim      opc = 2; // 0b0010
332226584Sdim    }
333245431Sdim    if (Ctx && ARM_AM::getSOImmVal(Value) == -1)
334245431Sdim      Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value");
335226584Sdim    // Encode the immediate and shift the opcode into place.
336226584Sdim    return ARM_AM::getSOImmVal(Value) | (opc << 21);
337226584Sdim  }
338226584Sdim
339226584Sdim  case ARM::fixup_t2_adr_pcrel_12: {
340226584Sdim    Value -= 4;
341226584Sdim    unsigned opc = 0;
342226584Sdim    if ((int64_t)Value < 0) {
343226584Sdim      Value = -Value;
344226584Sdim      opc = 5;
345226584Sdim    }
346226584Sdim
347226584Sdim    uint32_t out = (opc << 21);
348226584Sdim    out |= (Value & 0x800) << 15;
349226584Sdim    out |= (Value & 0x700) << 4;
350226584Sdim    out |= (Value & 0x0FF);
351226584Sdim
352226584Sdim    uint64_t swapped = (out & 0xFFFF0000) >> 16;
353226584Sdim    swapped |= (out & 0x0000FFFF) << 16;
354226584Sdim    return swapped;
355226584Sdim  }
356226584Sdim
357226584Sdim  case ARM::fixup_arm_condbranch:
358226584Sdim  case ARM::fixup_arm_uncondbranch:
359235633Sdim  case ARM::fixup_arm_uncondbl:
360235633Sdim  case ARM::fixup_arm_condbl:
361235633Sdim  case ARM::fixup_arm_blx:
362226584Sdim    // These values don't encode the low two bits since they're always zero.
363226584Sdim    // Offset by 8 just as above.
364226584Sdim    return 0xffffff & ((Value - 8) >> 2);
365226584Sdim  case ARM::fixup_t2_uncondbranch: {
366226584Sdim    Value = Value - 4;
367226584Sdim    Value >>= 1; // Low bit is not encoded.
368226584Sdim
369226584Sdim    uint32_t out = 0;
370226584Sdim    bool I =  Value & 0x800000;
371226584Sdim    bool J1 = Value & 0x400000;
372226584Sdim    bool J2 = Value & 0x200000;
373226584Sdim    J1 ^= I;
374226584Sdim    J2 ^= I;
375226584Sdim
376226584Sdim    out |= I  << 26; // S bit
377226584Sdim    out |= !J1 << 13; // J1 bit
378226584Sdim    out |= !J2 << 11; // J2 bit
379226584Sdim    out |= (Value & 0x1FF800)  << 5; // imm6 field
380226584Sdim    out |= (Value & 0x0007FF);        // imm11 field
381226584Sdim
382226584Sdim    uint64_t swapped = (out & 0xFFFF0000) >> 16;
383226584Sdim    swapped |= (out & 0x0000FFFF) << 16;
384226584Sdim    return swapped;
385226584Sdim  }
386226584Sdim  case ARM::fixup_t2_condbranch: {
387226584Sdim    Value = Value - 4;
388226584Sdim    Value >>= 1; // Low bit is not encoded.
389226584Sdim
390226584Sdim    uint64_t out = 0;
391226584Sdim    out |= (Value & 0x80000) << 7; // S bit
392226584Sdim    out |= (Value & 0x40000) >> 7; // J2 bit
393226584Sdim    out |= (Value & 0x20000) >> 4; // J1 bit
394226584Sdim    out |= (Value & 0x1F800) << 5; // imm6 field
395226584Sdim    out |= (Value & 0x007FF);      // imm11 field
396226584Sdim
397226584Sdim    uint32_t swapped = (out & 0xFFFF0000) >> 16;
398226584Sdim    swapped |= (out & 0x0000FFFF) << 16;
399226584Sdim    return swapped;
400226584Sdim  }
401226584Sdim  case ARM::fixup_arm_thumb_bl: {
402245431Sdim     // The value doesn't encode the low bit (always zero) and is offset by
403245431Sdim     // four. The 32-bit immediate value is encoded as
404245431Sdim     //   imm32 = SignExtend(S:I1:I2:imm10:imm11:0)
405245431Sdim     // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S).
406245431Sdim     // The value is encoded into disjoint bit positions in the destination
407245431Sdim     // opcode. x = unchanged, I = immediate value bit, S = sign extension bit,
408245431Sdim     // J = either J1 or J2 bit
409245431Sdim     //
410245431Sdim     //   BL:  xxxxxSIIIIIIIIII xxJxJIIIIIIIIIII
411245431Sdim     //
412245431Sdim     // Note that the halfwords are stored high first, low second; so we need
413245431Sdim     // to transpose the fixup value here to map properly.
414245431Sdim     uint32_t offset = (Value - 4) >> 1;
415245431Sdim     uint32_t signBit = (offset & 0x800000) >> 23;
416245431Sdim     uint32_t I1Bit = (offset & 0x400000) >> 22;
417245431Sdim     uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit;
418245431Sdim     uint32_t I2Bit = (offset & 0x200000) >> 21;
419245431Sdim     uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit;
420245431Sdim     uint32_t imm10Bits = (offset & 0x1FF800) >> 11;
421245431Sdim     uint32_t imm11Bits = (offset & 0x000007FF);
422263509Sdim
423245431Sdim     uint32_t Binary = 0;
424245431Sdim     uint32_t firstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10Bits);
425245431Sdim     uint32_t secondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) |
426245431Sdim                           (uint16_t)imm11Bits);
427245431Sdim     Binary |= secondHalf << 16;
428245431Sdim     Binary |= firstHalf;
429245431Sdim     return Binary;
430245431Sdim
431226584Sdim  }
432226584Sdim  case ARM::fixup_arm_thumb_blx: {
433245431Sdim     // The value doesn't encode the low two bits (always zero) and is offset by
434245431Sdim     // four (see fixup_arm_thumb_cp). The 32-bit immediate value is encoded as
435245431Sdim     //   imm32 = SignExtend(S:I1:I2:imm10H:imm10L:00)
436245431Sdim     // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S).
437263509Sdim     // The value is encoded into disjoint bit positions in the destination
438263509Sdim     // opcode. x = unchanged, I = immediate value bit, S = sign extension bit,
439245431Sdim     // J = either J1 or J2 bit, 0 = zero.
440245431Sdim     //
441245431Sdim     //   BLX: xxxxxSIIIIIIIIII xxJxJIIIIIIIIII0
442245431Sdim     //
443245431Sdim     // Note that the halfwords are stored high first, low second; so we need
444245431Sdim     // to transpose the fixup value here to map properly.
445245431Sdim     uint32_t offset = (Value - 2) >> 2;
446245431Sdim     uint32_t signBit = (offset & 0x400000) >> 22;
447245431Sdim     uint32_t I1Bit = (offset & 0x200000) >> 21;
448245431Sdim     uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit;
449245431Sdim     uint32_t I2Bit = (offset & 0x100000) >> 20;
450245431Sdim     uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit;
451245431Sdim     uint32_t imm10HBits = (offset & 0xFFC00) >> 10;
452245431Sdim     uint32_t imm10LBits = (offset & 0x3FF);
453263509Sdim
454245431Sdim     uint32_t Binary = 0;
455245431Sdim     uint32_t firstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10HBits);
456263509Sdim     uint32_t secondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) |
457245431Sdim                           ((uint16_t)imm10LBits) << 1);
458245431Sdim     Binary |= secondHalf << 16;
459245431Sdim     Binary |= firstHalf;
460245431Sdim     return Binary;
461226584Sdim  }
462226584Sdim  case ARM::fixup_arm_thumb_cp:
463226584Sdim    // Offset by 4, and don't encode the low two bits. Two bytes of that
464226584Sdim    // 'off by 4' is implicitly handled by the half-word ordering of the
465226584Sdim    // Thumb encoding, so we only need to adjust by 2 here.
466226584Sdim    return ((Value - 2) >> 2) & 0xff;
467226584Sdim  case ARM::fixup_arm_thumb_cb: {
468226584Sdim    // Offset by 4 and don't encode the lower bit, which is always 0.
469226584Sdim    uint32_t Binary = (Value - 4) >> 1;
470226584Sdim    return ((Binary & 0x20) << 4) | ((Binary & 0x1f) << 3);
471226584Sdim  }
472226584Sdim  case ARM::fixup_arm_thumb_br:
473226584Sdim    // Offset by 4 and don't encode the lower bit, which is always 0.
474226584Sdim    return ((Value - 4) >> 1) & 0x7ff;
475226584Sdim  case ARM::fixup_arm_thumb_bcc:
476226584Sdim    // Offset by 4 and don't encode the lower bit, which is always 0.
477226584Sdim    return ((Value - 4) >> 1) & 0xff;
478235633Sdim  case ARM::fixup_arm_pcrel_10_unscaled: {
479235633Sdim    Value = Value - 8; // ARM fixups offset by an additional word and don't
480235633Sdim                       // need to adjust for the half-word ordering.
481235633Sdim    bool isAdd = true;
482235633Sdim    if ((int64_t)Value < 0) {
483235633Sdim      Value = -Value;
484235633Sdim      isAdd = false;
485235633Sdim    }
486235633Sdim    // The value has the low 4 bits encoded in [3:0] and the high 4 in [11:8].
487245431Sdim    if (Ctx && Value >= 256)
488245431Sdim      Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value");
489235633Sdim    Value = (Value & 0xf) | ((Value & 0xf0) << 4);
490235633Sdim    return Value | (isAdd << 23);
491235633Sdim  }
492226584Sdim  case ARM::fixup_arm_pcrel_10:
493226584Sdim    Value = Value - 4; // ARM fixups offset by an additional word and don't
494226584Sdim                       // need to adjust for the half-word ordering.
495226584Sdim    // Fall through.
496226584Sdim  case ARM::fixup_t2_pcrel_10: {
497226584Sdim    // Offset by 4, adjusted by two due to the half-word ordering of thumb.
498226584Sdim    Value = Value - 4;
499226584Sdim    bool isAdd = true;
500226584Sdim    if ((int64_t)Value < 0) {
501226584Sdim      Value = -Value;
502226584Sdim      isAdd = false;
503226584Sdim    }
504226584Sdim    // These values don't encode the low two bits since they're always zero.
505226584Sdim    Value >>= 2;
506245431Sdim    if (Ctx && Value >= 256)
507245431Sdim      Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value");
508226584Sdim    Value |= isAdd << 23;
509226584Sdim
510235633Sdim    // Same addressing mode as fixup_arm_pcrel_10, but with 16-bit halfwords
511235633Sdim    // swapped.
512226584Sdim    if (Kind == ARM::fixup_t2_pcrel_10) {
513226584Sdim      uint32_t swapped = (Value & 0xFFFF0000) >> 16;
514226584Sdim      swapped |= (Value & 0x0000FFFF) << 16;
515226584Sdim      return swapped;
516226584Sdim    }
517226584Sdim
518226584Sdim    return Value;
519226584Sdim  }
520226584Sdim  }
521226584Sdim}
522226584Sdim
523245431Sdimvoid ARMAsmBackend::processFixupValue(const MCAssembler &Asm,
524245431Sdim                                      const MCAsmLayout &Layout,
525245431Sdim                                      const MCFixup &Fixup,
526245431Sdim                                      const MCFragment *DF,
527245431Sdim                                      MCValue &Target, uint64_t &Value,
528245431Sdim                                      bool &IsResolved) {
529245431Sdim  const MCSymbolRefExpr *A = Target.getSymA();
530245431Sdim  // Some fixups to thumb function symbols need the low bit (thumb bit)
531245431Sdim  // twiddled.
532245431Sdim  if ((unsigned)Fixup.getKind() != ARM::fixup_arm_ldst_pcrel_12 &&
533245431Sdim      (unsigned)Fixup.getKind() != ARM::fixup_t2_ldst_pcrel_12 &&
534245431Sdim      (unsigned)Fixup.getKind() != ARM::fixup_arm_adr_pcrel_12 &&
535245431Sdim      (unsigned)Fixup.getKind() != ARM::fixup_thumb_adr_pcrel_10 &&
536245431Sdim      (unsigned)Fixup.getKind() != ARM::fixup_t2_adr_pcrel_12 &&
537245431Sdim      (unsigned)Fixup.getKind() != ARM::fixup_arm_thumb_cp) {
538245431Sdim    if (A) {
539245431Sdim      const MCSymbol &Sym = A->getSymbol().AliasedSymbol();
540245431Sdim      if (Asm.isThumbFunc(&Sym))
541245431Sdim        Value |= 1;
542245431Sdim    }
543245431Sdim  }
544245431Sdim  // We must always generate a relocation for BL/BLX instructions if we have
545245431Sdim  // a symbol to reference, as the linker relies on knowing the destination
546245431Sdim  // symbol's thumb-ness to get interworking right.
547245431Sdim  if (A && ((unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_blx ||
548245431Sdim            (unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_bl ||
549245431Sdim            (unsigned)Fixup.getKind() == ARM::fixup_arm_blx ||
550245431Sdim            (unsigned)Fixup.getKind() == ARM::fixup_arm_uncondbl ||
551245431Sdim            (unsigned)Fixup.getKind() == ARM::fixup_arm_condbl))
552245431Sdim    IsResolved = false;
553245431Sdim
554245431Sdim  // Try to get the encoded value for the fixup as-if we're mapping it into
555245431Sdim  // the instruction. This allows adjustFixupValue() to issue a diagnostic
556245431Sdim  // if the value aren't invalid.
557245431Sdim  (void)adjustFixupValue(Fixup, Value, &Asm.getContext());
558245431Sdim}
559245431Sdim
560226584Sdim/// getFixupKindNumBytes - The number of bytes the fixup may change.
561226584Sdimstatic unsigned getFixupKindNumBytes(unsigned Kind) {
562226584Sdim  switch (Kind) {
563226584Sdim  default:
564226584Sdim    llvm_unreachable("Unknown fixup kind!");
565226584Sdim
566226584Sdim  case FK_Data_1:
567226584Sdim  case ARM::fixup_arm_thumb_bcc:
568226584Sdim  case ARM::fixup_arm_thumb_cp:
569226584Sdim  case ARM::fixup_thumb_adr_pcrel_10:
570226584Sdim    return 1;
571226584Sdim
572226584Sdim  case FK_Data_2:
573226584Sdim  case ARM::fixup_arm_thumb_br:
574226584Sdim  case ARM::fixup_arm_thumb_cb:
575226584Sdim    return 2;
576226584Sdim
577235633Sdim  case ARM::fixup_arm_pcrel_10_unscaled:
578226584Sdim  case ARM::fixup_arm_ldst_pcrel_12:
579226584Sdim  case ARM::fixup_arm_pcrel_10:
580226584Sdim  case ARM::fixup_arm_adr_pcrel_12:
581235633Sdim  case ARM::fixup_arm_uncondbl:
582235633Sdim  case ARM::fixup_arm_condbl:
583235633Sdim  case ARM::fixup_arm_blx:
584226584Sdim  case ARM::fixup_arm_condbranch:
585226584Sdim  case ARM::fixup_arm_uncondbranch:
586226584Sdim    return 3;
587226584Sdim
588226584Sdim  case FK_Data_4:
589226584Sdim  case ARM::fixup_t2_ldst_pcrel_12:
590226584Sdim  case ARM::fixup_t2_condbranch:
591226584Sdim  case ARM::fixup_t2_uncondbranch:
592226584Sdim  case ARM::fixup_t2_pcrel_10:
593226584Sdim  case ARM::fixup_t2_adr_pcrel_12:
594226584Sdim  case ARM::fixup_arm_thumb_bl:
595226584Sdim  case ARM::fixup_arm_thumb_blx:
596226584Sdim  case ARM::fixup_arm_movt_hi16:
597226584Sdim  case ARM::fixup_arm_movw_lo16:
598226584Sdim  case ARM::fixup_arm_movt_hi16_pcrel:
599226584Sdim  case ARM::fixup_arm_movw_lo16_pcrel:
600226584Sdim  case ARM::fixup_t2_movt_hi16:
601226584Sdim  case ARM::fixup_t2_movw_lo16:
602226584Sdim  case ARM::fixup_t2_movt_hi16_pcrel:
603226584Sdim  case ARM::fixup_t2_movw_lo16_pcrel:
604226584Sdim    return 4;
605226584Sdim  }
606226584Sdim}
607226584Sdim
608252723Sdimvoid ARMAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
609252723Sdim                               unsigned DataSize, uint64_t Value) const {
610226584Sdim  unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
611245431Sdim  Value = adjustFixupValue(Fixup, Value);
612226584Sdim  if (!Value) return;           // Doesn't change encoding.
613226584Sdim
614226584Sdim  unsigned Offset = Fixup.getOffset();
615226584Sdim  assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
616226584Sdim
617252723Sdim  // For each byte of the fragment that the fixup touches, mask in the bits from
618252723Sdim  // the fixup value. The Value has been "split up" into the appropriate
619252723Sdim  // bitfields above.
620226584Sdim  for (unsigned i = 0; i != NumBytes; ++i)
621226584Sdim    Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
622226584Sdim}
623226584Sdim
624252723Sdimnamespace {
625252723Sdim
626252723Sdim// FIXME: This should be in a separate file.
627252723Sdim// ELF is an ELF of course...
628252723Sdimclass ELFARMAsmBackend : public ARMAsmBackend {
629252723Sdimpublic:
630252723Sdim  uint8_t OSABI;
631252723Sdim  ELFARMAsmBackend(const Target &T, const StringRef TT,
632252723Sdim                   uint8_t _OSABI)
633252723Sdim    : ARMAsmBackend(T, TT), OSABI(_OSABI) { }
634252723Sdim
635252723Sdim  MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
636252723Sdim    return createARMELFObjectWriter(OS, OSABI);
637252723Sdim  }
638252723Sdim};
639252723Sdim
640252723Sdim// FIXME: This should be in a separate file.
641252723Sdimclass DarwinARMAsmBackend : public ARMAsmBackend {
642252723Sdimpublic:
643263509Sdim  const MachO::CPUSubTypeARM Subtype;
644252723Sdim  DarwinARMAsmBackend(const Target &T, const StringRef TT,
645263509Sdim                      MachO::CPUSubTypeARM st)
646252723Sdim    : ARMAsmBackend(T, TT), Subtype(st) {
647252723Sdim      HasDataInCodeSupport = true;
648252723Sdim    }
649252723Sdim
650252723Sdim  MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
651252723Sdim    return createARMMachObjectWriter(OS, /*Is64Bit=*/false,
652263509Sdim                                     MachO::CPU_TYPE_ARM,
653252723Sdim                                     Subtype);
654252723Sdim  }
655252723Sdim
656252723Sdim  virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
657252723Sdim    return false;
658252723Sdim  }
659252723Sdim};
660252723Sdim
661226584Sdim} // end anonymous namespace
662226584Sdim
663263509SdimMCAsmBackend *llvm::createARMAsmBackend(const Target &T,
664263509Sdim                                        const MCRegisterInfo &MRI,
665263509Sdim                                        StringRef TT, StringRef CPU) {
666226584Sdim  Triple TheTriple(TT);
667226584Sdim
668226584Sdim  if (TheTriple.isOSDarwin()) {
669263509Sdim    MachO::CPUSubTypeARM CS =
670263509Sdim      StringSwitch<MachO::CPUSubTypeARM>(TheTriple.getArchName())
671263509Sdim      .Cases("armv4t", "thumbv4t", MachO::CPU_SUBTYPE_ARM_V4T)
672263509Sdim      .Cases("armv5e", "thumbv5e", MachO::CPU_SUBTYPE_ARM_V5TEJ)
673263509Sdim      .Cases("armv6", "thumbv6", MachO::CPU_SUBTYPE_ARM_V6)
674263509Sdim      .Cases("armv6m", "thumbv6m", MachO::CPU_SUBTYPE_ARM_V6M)
675263509Sdim      .Cases("armv7em", "thumbv7em", MachO::CPU_SUBTYPE_ARM_V7EM)
676263509Sdim      .Cases("armv7f", "thumbv7f", MachO::CPU_SUBTYPE_ARM_V7F)
677263509Sdim      .Cases("armv7k", "thumbv7k", MachO::CPU_SUBTYPE_ARM_V7K)
678263509Sdim      .Cases("armv7m", "thumbv7m", MachO::CPU_SUBTYPE_ARM_V7M)
679263509Sdim      .Cases("armv7s", "thumbv7s", MachO::CPU_SUBTYPE_ARM_V7S)
680263509Sdim      .Default(MachO::CPU_SUBTYPE_ARM_V7);
681252723Sdim
682252723Sdim    return new DarwinARMAsmBackend(T, TT, CS);
683226584Sdim  }
684226584Sdim
685263509Sdim#if 0
686263509Sdim  // FIXME: Introduce yet another checker but assert(0).
687263509Sdim  if (TheTriple.isOSBinFormatCOFF())
688226584Sdim    assert(0 && "Windows not supported on ARM");
689263509Sdim#endif
690226584Sdim
691235633Sdim  uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS());
692235633Sdim  return new ELFARMAsmBackend(T, TT, OSABI);
693226584Sdim}
694