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