| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 1 | //===-- ARMAsmBackend.cpp - ARM Assembler Backend -------------------------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 10 | #include "MCTargetDesc/ARMMCTargetDesc.h" | 
| Chandler Carruth | ed0881b | 2012-12-03 16:50:05 +0000 | [diff] [blame] | 11 | #include "MCTargetDesc/ARMAddressingModes.h" | 
| Evan Cheng | ad5f485 | 2011-07-23 00:00:19 +0000 | [diff] [blame] | 12 | #include "MCTargetDesc/ARMBaseInfo.h" | 
|  | 13 | #include "MCTargetDesc/ARMFixupKinds.h" | 
| Quentin Colombet | 77ca8b8 | 2013-01-14 21:34:09 +0000 | [diff] [blame] | 14 | #include "llvm/ADT/StringSwitch.h" | 
| Chandler Carruth | ed0881b | 2012-12-03 16:50:05 +0000 | [diff] [blame] | 15 | #include "llvm/MC/MCAsmBackend.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 16 | #include "llvm/MC/MCAssembler.h" | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 17 | #include "llvm/MC/MCContext.h" | 
| Jim Grosbach | 87055ed | 2010-12-08 01:16:55 +0000 | [diff] [blame] | 18 | #include "llvm/MC/MCDirectives.h" | 
| Rafael Espindola | f0e24d4 | 2010-12-17 16:59:53 +0000 | [diff] [blame] | 19 | #include "llvm/MC/MCELFObjectWriter.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 20 | #include "llvm/MC/MCExpr.h" | 
| Craig Topper | 6e80c28 | 2012-03-26 06:58:25 +0000 | [diff] [blame] | 21 | #include "llvm/MC/MCFixupKindInfo.h" | 
| Daniel Dunbar | 73b8713 | 2010-12-16 16:08:33 +0000 | [diff] [blame] | 22 | #include "llvm/MC/MCMachObjectWriter.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 23 | #include "llvm/MC/MCObjectWriter.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 24 | #include "llvm/MC/MCSectionELF.h" | 
|  | 25 | #include "llvm/MC/MCSectionMachO.h" | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 26 | #include "llvm/MC/MCSubtargetInfo.h" | 
| Jim Grosbach | 3b50c9e | 2012-01-18 00:23:57 +0000 | [diff] [blame] | 27 | #include "llvm/MC/MCValue.h" | 
| Wesley Peck | 1851090 | 2010-10-22 15:52:49 +0000 | [diff] [blame] | 28 | #include "llvm/Support/ELF.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 29 | #include "llvm/Support/ErrorHandling.h" | 
| Charles Davis | 8bdfafd | 2013-09-01 04:28:48 +0000 | [diff] [blame] | 30 | #include "llvm/Support/MachO.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 31 | #include "llvm/Support/raw_ostream.h" | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 32 | using namespace llvm; | 
|  | 33 |  | 
|  | 34 | namespace { | 
| Rafael Espindola | 6b5e56c | 2010-12-17 17:45:22 +0000 | [diff] [blame] | 35 | class ARMELFObjectWriter : public MCELFObjectTargetWriter { | 
|  | 36 | public: | 
| Rafael Espindola | 1ad4095 | 2011-12-21 17:00:36 +0000 | [diff] [blame] | 37 | ARMELFObjectWriter(uint8_t OSABI) | 
|  | 38 | : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, ELF::EM_ARM, | 
| Rafael Espindola | fdaae0d | 2010-12-18 03:27:34 +0000 | [diff] [blame] | 39 | /*HasRelocationAddend*/ false) {} | 
| Rafael Espindola | 6b5e56c | 2010-12-17 17:45:22 +0000 | [diff] [blame] | 40 | }; | 
|  | 41 |  | 
| Evan Cheng | 5928e69 | 2011-07-25 23:24:55 +0000 | [diff] [blame] | 42 | class ARMAsmBackend : public MCAsmBackend { | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 43 | const MCSubtargetInfo* STI; | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 44 | bool isThumbMode;     // Currently emitting Thumb code. | 
|  | 45 | bool IsLittleEndian;  // Big or little endian. | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 46 | public: | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 47 | ARMAsmBackend(const Target &T, const StringRef TT, bool IsLittle) | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 48 | : MCAsmBackend(), STI(ARM_MC::createARMMCSubtargetInfo(TT, "", "")), | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 49 | isThumbMode(TT.startswith("thumb")), IsLittleEndian(IsLittle) {} | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 50 |  | 
|  | 51 | ~ARMAsmBackend() { | 
|  | 52 | delete STI; | 
|  | 53 | } | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 54 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 55 | unsigned getNumFixupKinds() const override { | 
|  | 56 | return ARM::NumTargetFixupKinds; | 
|  | 57 | } | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 58 |  | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 59 | bool hasNOP() const { | 
|  | 60 | return (STI->getFeatureBits() & ARM::HasV6T2Ops) != 0; | 
|  | 61 | } | 
|  | 62 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 63 | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 64 | const static MCFixupKindInfo InfosLE[ARM::NumTargetFixupKinds] = { | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 65 | // This table *must* be in the order that the fixup_* kinds are defined in | 
|  | 66 | // ARMFixupKinds.h. | 
|  | 67 | // | 
|  | 68 | // Name                      Offset (bits) Size (bits)     Flags | 
| Jim Grosbach | d3f02cb | 2011-11-16 22:48:37 +0000 | [diff] [blame] | 69 | { "fixup_arm_ldst_pcrel_12", 0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 70 | { "fixup_t2_ldst_pcrel_12",  0,            32,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 71 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
| Jim Grosbach | 8648c10 | 2011-12-19 23:06:24 +0000 | [diff] [blame] | 72 | { "fixup_arm_pcrel_10_unscaled", 0,        32,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Jim Grosbach | fb2f1d6 | 2011-11-01 01:24:45 +0000 | [diff] [blame] | 73 | { "fixup_arm_pcrel_10",      0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 74 | { "fixup_t2_pcrel_10",       0,            32,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 75 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
|  | 76 | { "fixup_thumb_adr_pcrel_10",0,            8,   MCFixupKindInfo::FKF_IsPCRel | | 
|  | 77 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
| Jim Grosbach | d3f02cb | 2011-11-16 22:48:37 +0000 | [diff] [blame] | 78 | { "fixup_arm_adr_pcrel_12",  0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 79 | { "fixup_t2_adr_pcrel_12",   0,            32,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 80 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
| Jason W Kim | d2e2f56 | 2011-02-04 19:47:15 +0000 | [diff] [blame] | 81 | { "fixup_arm_condbranch",    0,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 82 | { "fixup_arm_uncondbranch",  0,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 83 | { "fixup_t2_condbranch",     0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 84 | { "fixup_t2_uncondbranch",   0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 85 | { "fixup_arm_thumb_br",      0,            16,  MCFixupKindInfo::FKF_IsPCRel }, | 
| James Molloy | fb5cd60 | 2012-03-30 09:15:32 +0000 | [diff] [blame] | 86 | { "fixup_arm_uncondbl",      0,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 87 | { "fixup_arm_condbl",        0,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Jim Grosbach | 7b811d3 | 2012-02-27 21:36:23 +0000 | [diff] [blame] | 88 | { "fixup_arm_blx",           0,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 89 | { "fixup_arm_thumb_bl",      0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Jim Grosbach | f00b9cc | 2011-08-18 16:57:50 +0000 | [diff] [blame] | 90 | { "fixup_arm_thumb_blx",     0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 91 | { "fixup_arm_thumb_cb",      0,            16,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Jim Grosbach | 3d6c629 | 2012-04-26 20:48:12 +0000 | [diff] [blame] | 92 | { "fixup_arm_thumb_cp",      0,             8,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 93 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
| Eric Christopher | 368976f | 2011-05-28 03:16:22 +0000 | [diff] [blame] | 94 | { "fixup_arm_thumb_bcc",     0,             8,  MCFixupKindInfo::FKF_IsPCRel }, | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 95 | // movw / movt: 16-bits immediate but scattered into two chunks 0 - 12, 16 - 19. | 
|  | 96 | { "fixup_arm_movt_hi16",     0,            20,  0 }, | 
|  | 97 | { "fixup_arm_movw_lo16",     0,            20,  0 }, | 
|  | 98 | { "fixup_t2_movt_hi16",      0,            20,  0 }, | 
|  | 99 | { "fixup_t2_movw_lo16",      0,            20,  0 }, | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 100 | }; | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 101 | const static MCFixupKindInfo InfosBE[ARM::NumTargetFixupKinds] = { | 
|  | 102 | // This table *must* be in the order that the fixup_* kinds are defined in | 
|  | 103 | // ARMFixupKinds.h. | 
|  | 104 | // | 
|  | 105 | // Name                      Offset (bits) Size (bits)     Flags | 
|  | 106 | { "fixup_arm_ldst_pcrel_12", 0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 107 | { "fixup_t2_ldst_pcrel_12",  0,            32,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 108 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
|  | 109 | { "fixup_arm_pcrel_10_unscaled", 0,        32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 110 | { "fixup_arm_pcrel_10",      0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 111 | { "fixup_t2_pcrel_10",       0,            32,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 112 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
|  | 113 | { "fixup_thumb_adr_pcrel_10",8,            8,   MCFixupKindInfo::FKF_IsPCRel | | 
|  | 114 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
|  | 115 | { "fixup_arm_adr_pcrel_12",  0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 116 | { "fixup_t2_adr_pcrel_12",   0,            32,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 117 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
|  | 118 | { "fixup_arm_condbranch",    8,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 119 | { "fixup_arm_uncondbranch",  8,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 120 | { "fixup_t2_condbranch",     0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 121 | { "fixup_t2_uncondbranch",   0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 122 | { "fixup_arm_thumb_br",      0,            16,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 123 | { "fixup_arm_uncondbl",      8,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 124 | { "fixup_arm_condbl",        8,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 125 | { "fixup_arm_blx",           8,            24,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 126 | { "fixup_arm_thumb_bl",      0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 127 | { "fixup_arm_thumb_blx",     0,            32,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 128 | { "fixup_arm_thumb_cb",      0,            16,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 129 | { "fixup_arm_thumb_cp",      8,             8,  MCFixupKindInfo::FKF_IsPCRel | | 
|  | 130 | MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, | 
|  | 131 | { "fixup_arm_thumb_bcc",     8,             8,  MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 132 | // movw / movt: 16-bits immediate but scattered into two chunks 0 - 12, 16 - 19. | 
|  | 133 | { "fixup_arm_movt_hi16",     12,           20,  0 }, | 
|  | 134 | { "fixup_arm_movw_lo16",     12,           20,  0 }, | 
|  | 135 | { "fixup_t2_movt_hi16",      12,           20,  0 }, | 
|  | 136 | { "fixup_t2_movw_lo16",      12,           20,  0 }, | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 137 | }; | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 138 |  | 
|  | 139 | if (Kind < FirstTargetFixupKind) | 
| Evan Cheng | 5928e69 | 2011-07-25 23:24:55 +0000 | [diff] [blame] | 140 | return MCAsmBackend::getFixupKindInfo(Kind); | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 141 |  | 
|  | 142 | assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && | 
|  | 143 | "Invalid kind!"); | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 144 | return (IsLittleEndian ? InfosLE : InfosBE)[Kind - FirstTargetFixupKind]; | 
| Daniel Dunbar | 0c9d9fd | 2010-12-16 03:20:06 +0000 | [diff] [blame] | 145 | } | 
|  | 146 |  | 
| Jim Grosbach | 3b50c9e | 2012-01-18 00:23:57 +0000 | [diff] [blame] | 147 | /// processFixupValue - Target hook to process the literal value of a fixup | 
|  | 148 | /// if necessary. | 
|  | 149 | void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, | 
|  | 150 | const MCFixup &Fixup, const MCFragment *DF, | 
| Rafael Espindola | 3e3de5e | 2014-03-28 16:06:09 +0000 | [diff] [blame] | 151 | const MCValue &Target, uint64_t &Value, | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 152 | bool &IsResolved) override; | 
| Jim Grosbach | 3b50c9e | 2012-01-18 00:23:57 +0000 | [diff] [blame] | 153 |  | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 154 |  | 
|  | 155 | void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 156 | uint64_t Value, bool IsPCRel) const override; | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 157 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 158 | bool mayNeedRelaxation(const MCInst &Inst) const override; | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 159 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 160 | bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, | 
| Eli Bendersky | 4d9ada0 | 2013-01-08 00:22:56 +0000 | [diff] [blame] | 161 | const MCRelaxableFragment *DF, | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 162 | const MCAsmLayout &Layout) const override; | 
| Jim Grosbach | 25b63fa | 2011-12-06 00:47:03 +0000 | [diff] [blame] | 163 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 164 | void relaxInstruction(const MCInst &Inst, MCInst &Res) const override; | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 165 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 166 | bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; | 
| Jim Grosbach | 7e87296 | 2010-09-30 17:45:51 +0000 | [diff] [blame] | 167 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 168 | void handleAssemblerFlag(MCAssemblerFlag Flag) override { | 
| Jim Grosbach | 87055ed | 2010-12-08 01:16:55 +0000 | [diff] [blame] | 169 | switch (Flag) { | 
|  | 170 | default: break; | 
|  | 171 | case MCAF_Code16: | 
|  | 172 | setIsThumb(true); | 
|  | 173 | break; | 
|  | 174 | case MCAF_Code32: | 
|  | 175 | setIsThumb(false); | 
|  | 176 | break; | 
|  | 177 | } | 
| Jim Grosbach | 7e87296 | 2010-09-30 17:45:51 +0000 | [diff] [blame] | 178 | } | 
| Jim Grosbach | 87055ed | 2010-12-08 01:16:55 +0000 | [diff] [blame] | 179 |  | 
|  | 180 | unsigned getPointerSize() const { return 4; } | 
|  | 181 | bool isThumb() const { return isThumbMode; } | 
|  | 182 | void setIsThumb(bool it) { isThumbMode = it; } | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 183 | bool isLittle() const { return IsLittleEndian; } | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 184 | }; | 
| Chris Lattner | 9fdd10d | 2010-11-17 05:41:32 +0000 | [diff] [blame] | 185 | } // end anonymous namespace | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 186 |  | 
| Jim Grosbach | 34a7c6d | 2011-12-05 23:45:46 +0000 | [diff] [blame] | 187 | static unsigned getRelaxedOpcode(unsigned Op) { | 
|  | 188 | switch (Op) { | 
|  | 189 | default: return Op; | 
| Jim Grosbach | cb80eb2 | 2012-01-18 21:54:16 +0000 | [diff] [blame] | 190 | case ARM::tBcc:       return ARM::t2Bcc; | 
| Mihai Popa | 8a9da5b | 2013-07-22 15:49:36 +0000 | [diff] [blame] | 191 | case ARM::tLDRpci:    return ARM::t2LDRpci; | 
| Jim Grosbach | 44e5c39 | 2012-01-19 02:09:38 +0000 | [diff] [blame] | 192 | case ARM::tADR:       return ARM::t2ADR; | 
| Jim Grosbach | c4aa60f | 2012-03-19 21:32:32 +0000 | [diff] [blame] | 193 | case ARM::tB:         return ARM::t2B; | 
| Kevin Enderby | 9bd296a | 2014-01-10 00:43:32 +0000 | [diff] [blame] | 194 | case ARM::tCBZ:       return ARM::tHINT; | 
|  | 195 | case ARM::tCBNZ:      return ARM::tHINT; | 
| Jim Grosbach | 34a7c6d | 2011-12-05 23:45:46 +0000 | [diff] [blame] | 196 | } | 
|  | 197 | } | 
|  | 198 |  | 
| Jim Grosbach | aba3de9 | 2012-01-18 18:52:16 +0000 | [diff] [blame] | 199 | bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst) const { | 
| Jim Grosbach | 34a7c6d | 2011-12-05 23:45:46 +0000 | [diff] [blame] | 200 | if (getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode()) | 
|  | 201 | return true; | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 202 | return false; | 
|  | 203 | } | 
|  | 204 |  | 
| Jim Grosbach | 25b63fa | 2011-12-06 00:47:03 +0000 | [diff] [blame] | 205 | bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, | 
|  | 206 | uint64_t Value, | 
| Eli Bendersky | 4d9ada0 | 2013-01-08 00:22:56 +0000 | [diff] [blame] | 207 | const MCRelaxableFragment *DF, | 
| Jim Grosbach | 25b63fa | 2011-12-06 00:47:03 +0000 | [diff] [blame] | 208 | const MCAsmLayout &Layout) const { | 
| Benjamin Kramer | 116e99a | 2012-01-19 21:11:13 +0000 | [diff] [blame] | 209 | switch ((unsigned)Fixup.getKind()) { | 
| Jim Grosbach | c4aa60f | 2012-03-19 21:32:32 +0000 | [diff] [blame] | 210 | case ARM::fixup_arm_thumb_br: { | 
|  | 211 | // Relaxing tB to t2B. tB has a signed 12-bit displacement with the | 
|  | 212 | // low bit being an implied zero. There's an implied +4 offset for the | 
|  | 213 | // branch, so we adjust the other way here to determine what's | 
|  | 214 | // encodable. | 
|  | 215 | // | 
|  | 216 | // Relax if the value is too big for a (signed) i8. | 
|  | 217 | int64_t Offset = int64_t(Value) - 4; | 
|  | 218 | return Offset > 2046 || Offset < -2048; | 
|  | 219 | } | 
| Jim Grosbach | cb80eb2 | 2012-01-18 21:54:16 +0000 | [diff] [blame] | 220 | case ARM::fixup_arm_thumb_bcc: { | 
|  | 221 | // Relaxing tBcc to t2Bcc. tBcc has a signed 9-bit displacement with the | 
|  | 222 | // low bit being an implied zero. There's an implied +4 offset for the | 
|  | 223 | // branch, so we adjust the other way here to determine what's | 
|  | 224 | // encodable. | 
|  | 225 | // | 
|  | 226 | // Relax if the value is too big for a (signed) i8. | 
|  | 227 | int64_t Offset = int64_t(Value) - 4; | 
|  | 228 | return Offset > 254 || Offset < -256; | 
|  | 229 | } | 
| Jim Grosbach | 44e5c39 | 2012-01-19 02:09:38 +0000 | [diff] [blame] | 230 | case ARM::fixup_thumb_adr_pcrel_10: | 
| Jim Grosbach | cb80eb2 | 2012-01-18 21:54:16 +0000 | [diff] [blame] | 231 | case ARM::fixup_arm_thumb_cp: { | 
| Jim Grosbach | b008df4 | 2012-01-19 01:50:30 +0000 | [diff] [blame] | 232 | // If the immediate is negative, greater than 1020, or not a multiple | 
|  | 233 | // of four, the wide version of the instruction must be used. | 
| Jim Grosbach | cb80eb2 | 2012-01-18 21:54:16 +0000 | [diff] [blame] | 234 | int64_t Offset = int64_t(Value) - 4; | 
| Jim Grosbach | b008df4 | 2012-01-19 01:50:30 +0000 | [diff] [blame] | 235 | return Offset > 1020 || Offset < 0 || Offset & 3; | 
| Jim Grosbach | cb80eb2 | 2012-01-18 21:54:16 +0000 | [diff] [blame] | 236 | } | 
| Kevin Enderby | 9bd296a | 2014-01-10 00:43:32 +0000 | [diff] [blame] | 237 | case ARM::fixup_arm_thumb_cb: | 
|  | 238 | // If we have a Thumb CBZ or CBNZ instruction and its target is the next | 
|  | 239 | // instruction it is is actually out of range for the instruction. | 
|  | 240 | // It will be changed to a NOP. | 
|  | 241 | int64_t Offset = (Value & ~1); | 
|  | 242 | return Offset == 2; | 
| Jim Grosbach | cb80eb2 | 2012-01-18 21:54:16 +0000 | [diff] [blame] | 243 | } | 
| Benjamin Kramer | 116e99a | 2012-01-19 21:11:13 +0000 | [diff] [blame] | 244 | llvm_unreachable("Unexpected fixup kind in fixupNeedsRelaxation()!"); | 
| Jim Grosbach | 25b63fa | 2011-12-06 00:47:03 +0000 | [diff] [blame] | 245 | } | 
|  | 246 |  | 
| Jim Grosbach | aba3de9 | 2012-01-18 18:52:16 +0000 | [diff] [blame] | 247 | void ARMAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const { | 
| Jim Grosbach | 34a7c6d | 2011-12-05 23:45:46 +0000 | [diff] [blame] | 248 | unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode()); | 
|  | 249 |  | 
|  | 250 | // Sanity check w/ diagnostic if we get here w/ a bogus instruction. | 
|  | 251 | if (RelaxedOp == Inst.getOpcode()) { | 
|  | 252 | SmallString<256> Tmp; | 
|  | 253 | raw_svector_ostream OS(Tmp); | 
|  | 254 | Inst.dump_pretty(OS); | 
|  | 255 | OS << "\n"; | 
|  | 256 | report_fatal_error("unexpected instruction to relax: " + OS.str()); | 
|  | 257 | } | 
|  | 258 |  | 
| Kevin Enderby | 9bd296a | 2014-01-10 00:43:32 +0000 | [diff] [blame] | 259 | // If we are changing Thumb CBZ or CBNZ instruction to a NOP, aka tHINT, we | 
|  | 260 | // have to change the operands too. | 
|  | 261 | if ((Inst.getOpcode() == ARM::tCBZ || Inst.getOpcode() == ARM::tCBNZ) && | 
|  | 262 | RelaxedOp == ARM::tHINT) { | 
|  | 263 | Res.setOpcode(RelaxedOp); | 
|  | 264 | Res.addOperand(MCOperand::CreateImm(0)); | 
|  | 265 | Res.addOperand(MCOperand::CreateImm(14)); | 
|  | 266 | Res.addOperand(MCOperand::CreateReg(0)); | 
|  | 267 | return; | 
|  | 268 | } | 
|  | 269 |  | 
|  | 270 | // The rest of instructions we're relaxing have the same operands. | 
| Jim Grosbach | 34a7c6d | 2011-12-05 23:45:46 +0000 | [diff] [blame] | 271 | // We just need to update to the proper opcode. | 
|  | 272 | Res = Inst; | 
|  | 273 | Res.setOpcode(RelaxedOp); | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 274 | } | 
|  | 275 |  | 
| Jim Grosbach | aba3de9 | 2012-01-18 18:52:16 +0000 | [diff] [blame] | 276 | bool ARMAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 277 | const uint16_t Thumb1_16bitNopEncoding = 0x46c0; // using MOV r8,r8 | 
|  | 278 | const uint16_t Thumb2_16bitNopEncoding = 0xbf00; // NOP | 
| David Sehr | 05176ca | 2012-12-05 21:01:27 +0000 | [diff] [blame] | 279 | const uint32_t ARMv4_NopEncoding = 0xe1a00000; // using MOV r0,r0 | 
| Jim Grosbach | 7ccdb7c | 2011-11-16 22:40:25 +0000 | [diff] [blame] | 280 | const uint32_t ARMv6T2_NopEncoding = 0xe320f000; // NOP | 
| Jim Grosbach | 87055ed | 2010-12-08 01:16:55 +0000 | [diff] [blame] | 281 | if (isThumb()) { | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 282 | const uint16_t nopEncoding = hasNOP() ? Thumb2_16bitNopEncoding | 
|  | 283 | : Thumb1_16bitNopEncoding; | 
| Jim Grosbach | 97f1de7 | 2010-12-17 19:03:02 +0000 | [diff] [blame] | 284 | uint64_t NumNops = Count / 2; | 
|  | 285 | for (uint64_t i = 0; i != NumNops; ++i) | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 286 | OW->Write16(nopEncoding); | 
| Jim Grosbach | 97f1de7 | 2010-12-17 19:03:02 +0000 | [diff] [blame] | 287 | if (Count & 1) | 
|  | 288 | OW->Write8(0); | 
| Jim Grosbach | 87055ed | 2010-12-08 01:16:55 +0000 | [diff] [blame] | 289 | return true; | 
|  | 290 | } | 
|  | 291 | // ARM mode | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 292 | const uint32_t nopEncoding = hasNOP() ? ARMv6T2_NopEncoding | 
|  | 293 | : ARMv4_NopEncoding; | 
| Jim Grosbach | 97f1de7 | 2010-12-17 19:03:02 +0000 | [diff] [blame] | 294 | uint64_t NumNops = Count / 4; | 
|  | 295 | for (uint64_t i = 0; i != NumNops; ++i) | 
| Jim Grosbach | 45e50d8 | 2011-08-16 17:06:20 +0000 | [diff] [blame] | 296 | OW->Write32(nopEncoding); | 
|  | 297 | // FIXME: should this function return false when unable to write exactly | 
|  | 298 | // 'Count' bytes with NOP encodings? | 
| Jim Grosbach | 97f1de7 | 2010-12-17 19:03:02 +0000 | [diff] [blame] | 299 | switch (Count % 4) { | 
|  | 300 | default: break; // No leftover bytes to write | 
|  | 301 | case 1: OW->Write8(0); break; | 
|  | 302 | case 2: OW->Write16(0); break; | 
|  | 303 | case 3: OW->Write16(0); OW->Write8(0xa0); break; | 
|  | 304 | } | 
|  | 305 |  | 
| Rafael Espindola | 0ed1543 | 2010-10-25 17:50:35 +0000 | [diff] [blame] | 306 | return true; | 
| Jim Grosbach | 58bce99 | 2010-09-30 03:20:34 +0000 | [diff] [blame] | 307 | } | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 308 |  | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 309 | static unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 310 | bool IsPCRel, MCContext *Ctx) { | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 311 | unsigned Kind = Fixup.getKind(); | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 312 | switch (Kind) { | 
|  | 313 | default: | 
|  | 314 | llvm_unreachable("Unknown fixup kind!"); | 
| Jim Grosbach | 4416dfa | 2010-12-17 18:39:10 +0000 | [diff] [blame] | 315 | case FK_Data_1: | 
|  | 316 | case FK_Data_2: | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 317 | case FK_Data_4: | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 318 | return Value; | 
| Jason W Kim | d5e6e54 | 2010-12-03 19:40:23 +0000 | [diff] [blame] | 319 | case ARM::fixup_arm_movt_hi16: | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 320 | if (!IsPCRel) | 
|  | 321 | Value >>= 16; | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 322 | // Fallthrough | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 323 | case ARM::fixup_arm_movw_lo16: { | 
| Jason W Kim | d5e6e54 | 2010-12-03 19:40:23 +0000 | [diff] [blame] | 324 | unsigned Hi4 = (Value & 0xF000) >> 12; | 
|  | 325 | unsigned Lo12 = Value & 0x0FFF; | 
|  | 326 | // inst{19-16} = Hi4; | 
|  | 327 | // inst{11-0} = Lo12; | 
|  | 328 | Value = (Hi4 << 16) | (Lo12); | 
|  | 329 | return Value; | 
|  | 330 | } | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 331 | case ARM::fixup_t2_movt_hi16: | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 332 | if (!IsPCRel) | 
|  | 333 | Value >>= 16; | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 334 | // Fallthrough | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 335 | case ARM::fixup_t2_movw_lo16: { | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 336 | unsigned Hi4 = (Value & 0xF000) >> 12; | 
|  | 337 | unsigned i = (Value & 0x800) >> 11; | 
|  | 338 | unsigned Mid3 = (Value & 0x700) >> 8; | 
|  | 339 | unsigned Lo8 = Value & 0x0FF; | 
|  | 340 | // inst{19-16} = Hi4; | 
|  | 341 | // inst{26} = i; | 
|  | 342 | // inst{14-12} = Mid3; | 
|  | 343 | // inst{7-0} = Lo8; | 
| Jim Grosbach | d76f43e | 2011-09-30 22:02:45 +0000 | [diff] [blame] | 344 | Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8); | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 345 | uint64_t swapped = (Value & 0xFFFF0000) >> 16; | 
|  | 346 | swapped |= (Value & 0x0000FFFF) << 16; | 
|  | 347 | return swapped; | 
|  | 348 | } | 
| Owen Anderson | 3e6ee1d | 2010-12-09 01:51:07 +0000 | [diff] [blame] | 349 | case ARM::fixup_arm_ldst_pcrel_12: | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 350 | // ARM PC-relative values are offset by 8. | 
| Owen Anderson | 3ef19d9 | 2010-12-09 20:27:52 +0000 | [diff] [blame] | 351 | Value -= 4; | 
| Owen Anderson | cb4d8f2 | 2010-12-09 21:34:47 +0000 | [diff] [blame] | 352 | // FALLTHROUGH | 
| Owen Anderson | 3e6ee1d | 2010-12-09 01:51:07 +0000 | [diff] [blame] | 353 | case ARM::fixup_t2_ldst_pcrel_12: { | 
|  | 354 | // Offset by 4, adjusted by two due to the half-word ordering of thumb. | 
| Owen Anderson | 3ef19d9 | 2010-12-09 20:27:52 +0000 | [diff] [blame] | 355 | Value -= 4; | 
| Owen Anderson | 3e6ee1d | 2010-12-09 01:51:07 +0000 | [diff] [blame] | 356 | bool isAdd = true; | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 357 | if ((int64_t)Value < 0) { | 
|  | 358 | Value = -Value; | 
|  | 359 | isAdd = false; | 
|  | 360 | } | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 361 | if (Ctx && Value >= 4096) | 
|  | 362 | Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 363 | Value |= isAdd << 23; | 
| Jim Grosbach | 3aeb867 | 2010-12-13 19:18:13 +0000 | [diff] [blame] | 364 |  | 
| Owen Anderson | 3e6ee1d | 2010-12-09 01:51:07 +0000 | [diff] [blame] | 365 | // Same addressing mode as fixup_arm_pcrel_10, | 
|  | 366 | // but with 16-bit halfwords swapped. | 
|  | 367 | if (Kind == ARM::fixup_t2_ldst_pcrel_12) { | 
|  | 368 | uint64_t swapped = (Value & 0xFFFF0000) >> 16; | 
|  | 369 | swapped |= (Value & 0x0000FFFF) << 16; | 
|  | 370 | return swapped; | 
|  | 371 | } | 
| Jim Grosbach | 3aeb867 | 2010-12-13 19:18:13 +0000 | [diff] [blame] | 372 |  | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 373 | return Value; | 
|  | 374 | } | 
| Jim Grosbach | 509dc2a | 2010-12-14 22:28:03 +0000 | [diff] [blame] | 375 | case ARM::fixup_thumb_adr_pcrel_10: | 
|  | 376 | return ((Value - 4) >> 2) & 0xff; | 
| Jim Grosbach | ce2bd8d | 2010-12-02 00:28:45 +0000 | [diff] [blame] | 377 | case ARM::fixup_arm_adr_pcrel_12: { | 
|  | 378 | // ARM PC-relative values are offset by 8. | 
|  | 379 | Value -= 8; | 
|  | 380 | unsigned opc = 4; // bits {24-21}. Default to add: 0b0100 | 
|  | 381 | if ((int64_t)Value < 0) { | 
|  | 382 | Value = -Value; | 
|  | 383 | opc = 2; // 0b0010 | 
|  | 384 | } | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 385 | if (Ctx && ARM_AM::getSOImmVal(Value) == -1) | 
|  | 386 | Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); | 
| Jim Grosbach | ce2bd8d | 2010-12-02 00:28:45 +0000 | [diff] [blame] | 387 | // Encode the immediate and shift the opcode into place. | 
|  | 388 | return ARM_AM::getSOImmVal(Value) | (opc << 21); | 
|  | 389 | } | 
| Jim Grosbach | e34793e | 2010-12-14 16:25:15 +0000 | [diff] [blame] | 390 |  | 
| Owen Anderson | 6d375e5 | 2010-12-14 00:36:49 +0000 | [diff] [blame] | 391 | case ARM::fixup_t2_adr_pcrel_12: { | 
|  | 392 | Value -= 4; | 
|  | 393 | unsigned opc = 0; | 
|  | 394 | if ((int64_t)Value < 0) { | 
|  | 395 | Value = -Value; | 
|  | 396 | opc = 5; | 
|  | 397 | } | 
|  | 398 |  | 
|  | 399 | uint32_t out = (opc << 21); | 
| Owen Anderson | 8543d4f | 2011-03-23 22:03:44 +0000 | [diff] [blame] | 400 | out |= (Value & 0x800) << 15; | 
| Owen Anderson | 6d375e5 | 2010-12-14 00:36:49 +0000 | [diff] [blame] | 401 | out |= (Value & 0x700) << 4; | 
|  | 402 | out |= (Value & 0x0FF); | 
| Jim Grosbach | e34793e | 2010-12-14 16:25:15 +0000 | [diff] [blame] | 403 |  | 
| Owen Anderson | 6d375e5 | 2010-12-14 00:36:49 +0000 | [diff] [blame] | 404 | uint64_t swapped = (out & 0xFFFF0000) >> 16; | 
|  | 405 | swapped |= (out & 0x0000FFFF) << 16; | 
|  | 406 | return swapped; | 
|  | 407 | } | 
| Jim Grosbach | e34793e | 2010-12-14 16:25:15 +0000 | [diff] [blame] | 408 |  | 
| Jason W Kim | d2e2f56 | 2011-02-04 19:47:15 +0000 | [diff] [blame] | 409 | case ARM::fixup_arm_condbranch: | 
|  | 410 | case ARM::fixup_arm_uncondbranch: | 
| James Molloy | fb5cd60 | 2012-03-30 09:15:32 +0000 | [diff] [blame] | 411 | case ARM::fixup_arm_uncondbl: | 
|  | 412 | case ARM::fixup_arm_condbl: | 
| Jim Grosbach | 7b811d3 | 2012-02-27 21:36:23 +0000 | [diff] [blame] | 413 | case ARM::fixup_arm_blx: | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 414 | // These values don't encode the low two bits since they're always zero. | 
|  | 415 | // Offset by 8 just as above. | 
| Saleem Abdulrasool | 6e00ca8 | 2014-01-30 04:02:31 +0000 | [diff] [blame] | 416 | if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Fixup.getValue())) | 
|  | 417 | if (SRE->getKind() == MCSymbolRefExpr::VK_ARM_TLSCALL) | 
|  | 418 | return 0; | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 419 | return 0xffffff & ((Value - 8) >> 2); | 
| Owen Anderson | 578074b | 2010-12-13 19:31:11 +0000 | [diff] [blame] | 420 | case ARM::fixup_t2_uncondbranch: { | 
| Owen Anderson | 235c276 | 2010-12-10 23:02:28 +0000 | [diff] [blame] | 421 | Value = Value - 4; | 
| Owen Anderson | 302d5fd | 2010-12-09 00:27:41 +0000 | [diff] [blame] | 422 | Value >>= 1; // Low bit is not encoded. | 
| Jim Grosbach | 3aeb867 | 2010-12-13 19:18:13 +0000 | [diff] [blame] | 423 |  | 
| Jim Grosbach | f588c51 | 2010-12-13 19:25:46 +0000 | [diff] [blame] | 424 | uint32_t out = 0; | 
| Owen Anderson | 578074b | 2010-12-13 19:31:11 +0000 | [diff] [blame] | 425 | bool I =  Value & 0x800000; | 
|  | 426 | bool J1 = Value & 0x400000; | 
|  | 427 | bool J2 = Value & 0x200000; | 
|  | 428 | J1 ^= I; | 
|  | 429 | J2 ^= I; | 
| Jim Grosbach | e34793e | 2010-12-14 16:25:15 +0000 | [diff] [blame] | 430 |  | 
| Owen Anderson | 578074b | 2010-12-13 19:31:11 +0000 | [diff] [blame] | 431 | out |= I  << 26; // S bit | 
|  | 432 | out |= !J1 << 13; // J1 bit | 
|  | 433 | out |= !J2 << 11; // J2 bit | 
|  | 434 | out |= (Value & 0x1FF800)  << 5; // imm6 field | 
|  | 435 | out |= (Value & 0x0007FF);        // imm11 field | 
| Jim Grosbach | e34793e | 2010-12-14 16:25:15 +0000 | [diff] [blame] | 436 |  | 
| Owen Anderson | 578074b | 2010-12-13 19:31:11 +0000 | [diff] [blame] | 437 | uint64_t swapped = (out & 0xFFFF0000) >> 16; | 
|  | 438 | swapped |= (out & 0x0000FFFF) << 16; | 
|  | 439 | return swapped; | 
|  | 440 | } | 
|  | 441 | case ARM::fixup_t2_condbranch: { | 
|  | 442 | Value = Value - 4; | 
|  | 443 | Value >>= 1; // Low bit is not encoded. | 
| Jim Grosbach | e34793e | 2010-12-14 16:25:15 +0000 | [diff] [blame] | 444 |  | 
| Owen Anderson | 578074b | 2010-12-13 19:31:11 +0000 | [diff] [blame] | 445 | uint64_t out = 0; | 
| Owen Anderson | 14e4127 | 2010-12-09 01:02:09 +0000 | [diff] [blame] | 446 | out |= (Value & 0x80000) << 7; // S bit | 
|  | 447 | out |= (Value & 0x40000) >> 7; // J2 bit | 
|  | 448 | out |= (Value & 0x20000) >> 4; // J1 bit | 
|  | 449 | out |= (Value & 0x1F800) << 5; // imm6 field | 
|  | 450 | out |= (Value & 0x007FF);      // imm11 field | 
| Jim Grosbach | 3aeb867 | 2010-12-13 19:18:13 +0000 | [diff] [blame] | 451 |  | 
| Jim Grosbach | f588c51 | 2010-12-13 19:25:46 +0000 | [diff] [blame] | 452 | uint32_t swapped = (out & 0xFFFF0000) >> 16; | 
| Owen Anderson | 302d5fd | 2010-12-09 00:27:41 +0000 | [diff] [blame] | 453 | swapped |= (out & 0x0000FFFF) << 16; | 
|  | 454 | return swapped; | 
|  | 455 | } | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 456 | case ARM::fixup_arm_thumb_bl: { | 
| Saleem Abdulrasool | 077fd25 | 2014-01-26 22:29:36 +0000 | [diff] [blame] | 457 | // The value doesn't encode the low bit (always zero) and is offset by | 
|  | 458 | // four. The 32-bit immediate value is encoded as | 
|  | 459 | //   imm32 = SignExtend(S:I1:I2:imm10:imm11:0) | 
|  | 460 | // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S). | 
|  | 461 | // The value is encoded into disjoint bit positions in the destination | 
|  | 462 | // opcode. x = unchanged, I = immediate value bit, S = sign extension bit, | 
|  | 463 | // J = either J1 or J2 bit | 
|  | 464 | // | 
|  | 465 | //   BL:  xxxxxSIIIIIIIIII xxJxJIIIIIIIIIII | 
|  | 466 | // | 
|  | 467 | // Note that the halfwords are stored high first, low second; so we need | 
|  | 468 | // to transpose the fixup value here to map properly. | 
|  | 469 | uint32_t offset = (Value - 4) >> 1; | 
|  | 470 | uint32_t signBit = (offset & 0x800000) >> 23; | 
|  | 471 | uint32_t I1Bit = (offset & 0x400000) >> 22; | 
|  | 472 | uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit; | 
|  | 473 | uint32_t I2Bit = (offset & 0x200000) >> 21; | 
|  | 474 | uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit; | 
|  | 475 | uint32_t imm10Bits = (offset & 0x1FF800) >> 11; | 
|  | 476 | uint32_t imm11Bits = (offset & 0x000007FF); | 
| NAKAMURA Takumi | 8018a29 | 2013-06-11 06:52:36 +0000 | [diff] [blame] | 477 |  | 
| Saleem Abdulrasool | 077fd25 | 2014-01-26 22:29:36 +0000 | [diff] [blame] | 478 | uint32_t Binary = 0; | 
|  | 479 | uint32_t firstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10Bits); | 
|  | 480 | uint32_t secondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) | | 
|  | 481 | (uint16_t)imm11Bits); | 
|  | 482 | Binary |= secondHalf << 16; | 
|  | 483 | Binary |= firstHalf; | 
|  | 484 | return Binary; | 
| Bill Wendling | 3392bfc | 2010-12-09 00:39:08 +0000 | [diff] [blame] | 485 | } | 
|  | 486 | case ARM::fixup_arm_thumb_blx: { | 
| Saleem Abdulrasool | 077fd25 | 2014-01-26 22:29:36 +0000 | [diff] [blame] | 487 | // The value doesn't encode the low two bits (always zero) and is offset by | 
|  | 488 | // four (see fixup_arm_thumb_cp). The 32-bit immediate value is encoded as | 
|  | 489 | //   imm32 = SignExtend(S:I1:I2:imm10H:imm10L:00) | 
|  | 490 | // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S). | 
|  | 491 | // The value is encoded into disjoint bit positions in the destination | 
|  | 492 | // opcode. x = unchanged, I = immediate value bit, S = sign extension bit, | 
|  | 493 | // J = either J1 or J2 bit, 0 = zero. | 
|  | 494 | // | 
|  | 495 | //   BLX: xxxxxSIIIIIIIIII xxJxJIIIIIIIIII0 | 
|  | 496 | // | 
|  | 497 | // Note that the halfwords are stored high first, low second; so we need | 
|  | 498 | // to transpose the fixup value here to map properly. | 
|  | 499 | uint32_t offset = (Value - 2) >> 2; | 
| Saleem Abdulrasool | 6e00ca8 | 2014-01-30 04:02:31 +0000 | [diff] [blame] | 500 | if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Fixup.getValue())) | 
|  | 501 | if (SRE->getKind() == MCSymbolRefExpr::VK_ARM_TLSCALL) | 
|  | 502 | offset = 0; | 
| Saleem Abdulrasool | 077fd25 | 2014-01-26 22:29:36 +0000 | [diff] [blame] | 503 | uint32_t signBit = (offset & 0x400000) >> 22; | 
|  | 504 | uint32_t I1Bit = (offset & 0x200000) >> 21; | 
|  | 505 | uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit; | 
|  | 506 | uint32_t I2Bit = (offset & 0x100000) >> 20; | 
|  | 507 | uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit; | 
|  | 508 | uint32_t imm10HBits = (offset & 0xFFC00) >> 10; | 
|  | 509 | uint32_t imm10LBits = (offset & 0x3FF); | 
| NAKAMURA Takumi | 8018a29 | 2013-06-11 06:52:36 +0000 | [diff] [blame] | 510 |  | 
| Saleem Abdulrasool | 077fd25 | 2014-01-26 22:29:36 +0000 | [diff] [blame] | 511 | uint32_t Binary = 0; | 
|  | 512 | uint32_t firstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10HBits); | 
|  | 513 | uint32_t secondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) | | 
|  | 514 | ((uint16_t)imm10LBits) << 1); | 
|  | 515 | Binary |= secondHalf << 16; | 
|  | 516 | Binary |= firstHalf; | 
|  | 517 | return Binary; | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 518 | } | 
| Bill Wendling | 8a6449c | 2010-12-08 01:57:09 +0000 | [diff] [blame] | 519 | case ARM::fixup_arm_thumb_cp: | 
| Jim Grosbach | 3c68561 | 2010-12-08 20:32:07 +0000 | [diff] [blame] | 520 | // Offset by 4, and don't encode the low two bits. Two bytes of that | 
|  | 521 | // 'off by 4' is implicitly handled by the half-word ordering of the | 
|  | 522 | // Thumb encoding, so we only need to adjust by 2 here. | 
|  | 523 | return ((Value - 2) >> 2) & 0xff; | 
| Jim Grosbach | 68b27eb | 2010-12-09 19:50:12 +0000 | [diff] [blame] | 524 | case ARM::fixup_arm_thumb_cb: { | 
| Bill Wendling | a7d6aa9 | 2010-12-08 23:01:43 +0000 | [diff] [blame] | 525 | // Offset by 4 and don't encode the lower bit, which is always 0. | 
|  | 526 | uint32_t Binary = (Value - 4) >> 1; | 
| Owen Anderson | f636a64 | 2010-12-14 19:42:53 +0000 | [diff] [blame] | 527 | return ((Binary & 0x20) << 4) | ((Binary & 0x1f) << 3); | 
| Bill Wendling | a7d6aa9 | 2010-12-08 23:01:43 +0000 | [diff] [blame] | 528 | } | 
| Jim Grosbach | e119da1 | 2010-12-10 18:21:33 +0000 | [diff] [blame] | 529 | case ARM::fixup_arm_thumb_br: | 
|  | 530 | // Offset by 4 and don't encode the lower bit, which is always 0. | 
|  | 531 | return ((Value - 4) >> 1) & 0x7ff; | 
| Jim Grosbach | 78485ad | 2010-12-10 17:13:40 +0000 | [diff] [blame] | 532 | case ARM::fixup_arm_thumb_bcc: | 
|  | 533 | // Offset by 4 and don't encode the lower bit, which is always 0. | 
|  | 534 | return ((Value - 4) >> 1) & 0xff; | 
| Jim Grosbach | 8648c10 | 2011-12-19 23:06:24 +0000 | [diff] [blame] | 535 | case ARM::fixup_arm_pcrel_10_unscaled: { | 
|  | 536 | Value = Value - 8; // ARM fixups offset by an additional word and don't | 
|  | 537 | // need to adjust for the half-word ordering. | 
|  | 538 | bool isAdd = true; | 
|  | 539 | if ((int64_t)Value < 0) { | 
|  | 540 | Value = -Value; | 
|  | 541 | isAdd = false; | 
|  | 542 | } | 
| Jim Grosbach | 913cc30 | 2012-03-30 21:54:22 +0000 | [diff] [blame] | 543 | // The value has the low 4 bits encoded in [3:0] and the high 4 in [11:8]. | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 544 | if (Ctx && Value >= 256) | 
|  | 545 | Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); | 
| Jim Grosbach | 913cc30 | 2012-03-30 21:54:22 +0000 | [diff] [blame] | 546 | Value = (Value & 0xf) | ((Value & 0xf0) << 4); | 
| Jim Grosbach | 8648c10 | 2011-12-19 23:06:24 +0000 | [diff] [blame] | 547 | return Value | (isAdd << 23); | 
|  | 548 | } | 
| Jim Grosbach | 3c68561 | 2010-12-08 20:32:07 +0000 | [diff] [blame] | 549 | case ARM::fixup_arm_pcrel_10: | 
| Owen Anderson | 4743d75 | 2010-12-10 22:46:47 +0000 | [diff] [blame] | 550 | Value = Value - 4; // ARM fixups offset by an additional word and don't | 
| Jim Grosbach | 3c68561 | 2010-12-08 20:32:07 +0000 | [diff] [blame] | 551 | // need to adjust for the half-word ordering. | 
|  | 552 | // Fall through. | 
|  | 553 | case ARM::fixup_t2_pcrel_10: { | 
|  | 554 | // Offset by 4, adjusted by two due to the half-word ordering of thumb. | 
| Owen Anderson | 4743d75 | 2010-12-10 22:46:47 +0000 | [diff] [blame] | 555 | Value = Value - 4; | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 556 | bool isAdd = true; | 
|  | 557 | if ((int64_t)Value < 0) { | 
|  | 558 | Value = -Value; | 
|  | 559 | isAdd = false; | 
|  | 560 | } | 
|  | 561 | // These values don't encode the low two bits since they're always zero. | 
|  | 562 | Value >>= 2; | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 563 | if (Ctx && Value >= 256) | 
|  | 564 | Ctx->FatalError(Fixup.getLoc(), "out of range pc-relative fixup value"); | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 565 | Value |= isAdd << 23; | 
| Jim Grosbach | 3c68561 | 2010-12-08 20:32:07 +0000 | [diff] [blame] | 566 |  | 
| Jim Grosbach | 8648c10 | 2011-12-19 23:06:24 +0000 | [diff] [blame] | 567 | // Same addressing mode as fixup_arm_pcrel_10, but with 16-bit halfwords | 
|  | 568 | // swapped. | 
| Owen Anderson | 0f7142d | 2010-12-08 00:18:36 +0000 | [diff] [blame] | 569 | if (Kind == ARM::fixup_t2_pcrel_10) { | 
| Jim Grosbach | f588c51 | 2010-12-13 19:25:46 +0000 | [diff] [blame] | 570 | uint32_t swapped = (Value & 0xFFFF0000) >> 16; | 
| Owen Anderson | 72ce453 | 2010-12-08 00:21:33 +0000 | [diff] [blame] | 571 | swapped |= (Value & 0x0000FFFF) << 16; | 
| Owen Anderson | 0f7142d | 2010-12-08 00:18:36 +0000 | [diff] [blame] | 572 | return swapped; | 
|  | 573 | } | 
| Jim Grosbach | 3c68561 | 2010-12-08 20:32:07 +0000 | [diff] [blame] | 574 |  | 
| Jason W Kim | fc5c522 | 2010-12-01 22:46:50 +0000 | [diff] [blame] | 575 | return Value; | 
|  | 576 | } | 
|  | 577 | } | 
|  | 578 | } | 
|  | 579 |  | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 580 | void ARMAsmBackend::processFixupValue(const MCAssembler &Asm, | 
|  | 581 | const MCAsmLayout &Layout, | 
|  | 582 | const MCFixup &Fixup, | 
|  | 583 | const MCFragment *DF, | 
| Rafael Espindola | 3e3de5e | 2014-03-28 16:06:09 +0000 | [diff] [blame] | 584 | const MCValue &Target, uint64_t &Value, | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 585 | bool &IsResolved) { | 
|  | 586 | const MCSymbolRefExpr *A = Target.getSymA(); | 
|  | 587 | // Some fixups to thumb function symbols need the low bit (thumb bit) | 
|  | 588 | // twiddled. | 
|  | 589 | if ((unsigned)Fixup.getKind() != ARM::fixup_arm_ldst_pcrel_12 && | 
|  | 590 | (unsigned)Fixup.getKind() != ARM::fixup_t2_ldst_pcrel_12 && | 
|  | 591 | (unsigned)Fixup.getKind() != ARM::fixup_arm_adr_pcrel_12 && | 
|  | 592 | (unsigned)Fixup.getKind() != ARM::fixup_thumb_adr_pcrel_10 && | 
|  | 593 | (unsigned)Fixup.getKind() != ARM::fixup_t2_adr_pcrel_12 && | 
|  | 594 | (unsigned)Fixup.getKind() != ARM::fixup_arm_thumb_cp) { | 
|  | 595 | if (A) { | 
|  | 596 | const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); | 
|  | 597 | if (Asm.isThumbFunc(&Sym)) | 
|  | 598 | Value |= 1; | 
|  | 599 | } | 
|  | 600 | } | 
| Logan Chien | d5c48aa | 2014-02-05 14:15:16 +0000 | [diff] [blame] | 601 | // For Thumb1 BL instruction, it is possible to be a long jump between | 
|  | 602 | // the basic blocks of the same function.  Thus, we would like to resolve | 
|  | 603 | // the offset when the destination has the same MCFragment. | 
|  | 604 | if (A && (unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_bl) { | 
|  | 605 | const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); | 
|  | 606 | MCSymbolData &SymData = Asm.getSymbolData(Sym); | 
|  | 607 | IsResolved = (SymData.getFragment() == DF); | 
|  | 608 | } | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 609 | // We must always generate a relocation for BL/BLX instructions if we have | 
|  | 610 | // a symbol to reference, as the linker relies on knowing the destination | 
|  | 611 | // symbol's thumb-ness to get interworking right. | 
|  | 612 | if (A && ((unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_blx || | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 613 | (unsigned)Fixup.getKind() == ARM::fixup_arm_blx || | 
|  | 614 | (unsigned)Fixup.getKind() == ARM::fixup_arm_uncondbl || | 
|  | 615 | (unsigned)Fixup.getKind() == ARM::fixup_arm_condbl)) | 
|  | 616 | IsResolved = false; | 
|  | 617 |  | 
|  | 618 | // Try to get the encoded value for the fixup as-if we're mapping it into | 
|  | 619 | // the instruction. This allows adjustFixupValue() to issue a diagnostic | 
|  | 620 | // if the value aren't invalid. | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 621 | (void)adjustFixupValue(Fixup, Value, false, &Asm.getContext()); | 
| Jim Grosbach | e78031a | 2012-04-30 22:30:43 +0000 | [diff] [blame] | 622 | } | 
|  | 623 |  | 
| Bill Wendling | f09c44c | 2010-12-07 23:11:00 +0000 | [diff] [blame] | 624 | /// getFixupKindNumBytes - The number of bytes the fixup may change. | 
| Jim Grosbach | 9d6d77a | 2010-11-11 18:04:49 +0000 | [diff] [blame] | 625 | static unsigned getFixupKindNumBytes(unsigned Kind) { | 
| Jim Grosbach | 9098714 | 2010-11-09 01:37:15 +0000 | [diff] [blame] | 626 | switch (Kind) { | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 627 | default: | 
|  | 628 | llvm_unreachable("Unknown fixup kind!"); | 
| Bill Wendling | 8a6449c | 2010-12-08 01:57:09 +0000 | [diff] [blame] | 629 |  | 
| Jim Grosbach | 4416dfa | 2010-12-17 18:39:10 +0000 | [diff] [blame] | 630 | case FK_Data_1: | 
| Jim Grosbach | 78485ad | 2010-12-10 17:13:40 +0000 | [diff] [blame] | 631 | case ARM::fixup_arm_thumb_bcc: | 
| Bill Wendling | 8a6449c | 2010-12-08 01:57:09 +0000 | [diff] [blame] | 632 | case ARM::fixup_arm_thumb_cp: | 
| Jim Grosbach | 509dc2a | 2010-12-14 22:28:03 +0000 | [diff] [blame] | 633 | case ARM::fixup_thumb_adr_pcrel_10: | 
| Bill Wendling | 8a6449c | 2010-12-08 01:57:09 +0000 | [diff] [blame] | 634 | return 1; | 
|  | 635 |  | 
| Jim Grosbach | 4416dfa | 2010-12-17 18:39:10 +0000 | [diff] [blame] | 636 | case FK_Data_2: | 
| Jim Grosbach | e119da1 | 2010-12-10 18:21:33 +0000 | [diff] [blame] | 637 | case ARM::fixup_arm_thumb_br: | 
| Jim Grosbach | 68b27eb | 2010-12-09 19:50:12 +0000 | [diff] [blame] | 638 | case ARM::fixup_arm_thumb_cb: | 
| Bill Wendling | a7d6aa9 | 2010-12-08 23:01:43 +0000 | [diff] [blame] | 639 | return 2; | 
|  | 640 |  | 
| Jim Grosbach | 8648c10 | 2011-12-19 23:06:24 +0000 | [diff] [blame] | 641 | case ARM::fixup_arm_pcrel_10_unscaled: | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 642 | case ARM::fixup_arm_ldst_pcrel_12: | 
|  | 643 | case ARM::fixup_arm_pcrel_10: | 
|  | 644 | case ARM::fixup_arm_adr_pcrel_12: | 
| James Molloy | fb5cd60 | 2012-03-30 09:15:32 +0000 | [diff] [blame] | 645 | case ARM::fixup_arm_uncondbl: | 
|  | 646 | case ARM::fixup_arm_condbl: | 
| Jim Grosbach | 7b811d3 | 2012-02-27 21:36:23 +0000 | [diff] [blame] | 647 | case ARM::fixup_arm_blx: | 
| Jason W Kim | d2e2f56 | 2011-02-04 19:47:15 +0000 | [diff] [blame] | 648 | case ARM::fixup_arm_condbranch: | 
|  | 649 | case ARM::fixup_arm_uncondbranch: | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 650 | return 3; | 
| Bill Wendling | 8a6449c | 2010-12-08 01:57:09 +0000 | [diff] [blame] | 651 |  | 
|  | 652 | case FK_Data_4: | 
| Owen Anderson | 3e6ee1d | 2010-12-09 01:51:07 +0000 | [diff] [blame] | 653 | case ARM::fixup_t2_ldst_pcrel_12: | 
| Owen Anderson | 578074b | 2010-12-13 19:31:11 +0000 | [diff] [blame] | 654 | case ARM::fixup_t2_condbranch: | 
|  | 655 | case ARM::fixup_t2_uncondbranch: | 
| Owen Anderson | 0f7142d | 2010-12-08 00:18:36 +0000 | [diff] [blame] | 656 | case ARM::fixup_t2_pcrel_10: | 
| Owen Anderson | 6d375e5 | 2010-12-14 00:36:49 +0000 | [diff] [blame] | 657 | case ARM::fixup_t2_adr_pcrel_12: | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 658 | case ARM::fixup_arm_thumb_bl: | 
| Bill Wendling | 3392bfc | 2010-12-09 00:39:08 +0000 | [diff] [blame] | 659 | case ARM::fixup_arm_thumb_blx: | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 660 | case ARM::fixup_arm_movt_hi16: | 
|  | 661 | case ARM::fixup_arm_movw_lo16: | 
| Evan Cheng | d4a5c05 | 2011-01-14 02:38:49 +0000 | [diff] [blame] | 662 | case ARM::fixup_t2_movt_hi16: | 
|  | 663 | case ARM::fixup_t2_movw_lo16: | 
| Jim Grosbach | 9e19946 | 2010-12-06 23:57:07 +0000 | [diff] [blame] | 664 | return 4; | 
| Jim Grosbach | 9098714 | 2010-11-09 01:37:15 +0000 | [diff] [blame] | 665 | } | 
|  | 666 | } | 
|  | 667 |  | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 668 | /// getFixupKindContainerSizeBytes - The number of bytes of the | 
|  | 669 | /// container involved in big endian. | 
|  | 670 | static unsigned getFixupKindContainerSizeBytes(unsigned Kind) { | 
|  | 671 | switch (Kind) { | 
|  | 672 | default: | 
|  | 673 | llvm_unreachable("Unknown fixup kind!"); | 
|  | 674 |  | 
|  | 675 | case FK_Data_1: | 
|  | 676 | return 1; | 
|  | 677 | case FK_Data_2: | 
|  | 678 | return 2; | 
|  | 679 | case FK_Data_4: | 
|  | 680 | return 4; | 
|  | 681 |  | 
|  | 682 | case ARM::fixup_arm_thumb_bcc: | 
|  | 683 | case ARM::fixup_arm_thumb_cp: | 
|  | 684 | case ARM::fixup_thumb_adr_pcrel_10: | 
|  | 685 | case ARM::fixup_arm_thumb_br: | 
|  | 686 | case ARM::fixup_arm_thumb_cb: | 
|  | 687 | // Instruction size is 2 bytes. | 
|  | 688 | return 2; | 
|  | 689 |  | 
|  | 690 | case ARM::fixup_arm_pcrel_10_unscaled: | 
|  | 691 | case ARM::fixup_arm_ldst_pcrel_12: | 
|  | 692 | case ARM::fixup_arm_pcrel_10: | 
|  | 693 | case ARM::fixup_arm_adr_pcrel_12: | 
|  | 694 | case ARM::fixup_arm_uncondbl: | 
|  | 695 | case ARM::fixup_arm_condbl: | 
|  | 696 | case ARM::fixup_arm_blx: | 
|  | 697 | case ARM::fixup_arm_condbranch: | 
|  | 698 | case ARM::fixup_arm_uncondbranch: | 
|  | 699 | case ARM::fixup_t2_ldst_pcrel_12: | 
|  | 700 | case ARM::fixup_t2_condbranch: | 
|  | 701 | case ARM::fixup_t2_uncondbranch: | 
|  | 702 | case ARM::fixup_t2_pcrel_10: | 
|  | 703 | case ARM::fixup_t2_adr_pcrel_12: | 
|  | 704 | case ARM::fixup_arm_thumb_bl: | 
|  | 705 | case ARM::fixup_arm_thumb_blx: | 
|  | 706 | case ARM::fixup_arm_movt_hi16: | 
|  | 707 | case ARM::fixup_arm_movw_lo16: | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 708 | case ARM::fixup_t2_movt_hi16: | 
|  | 709 | case ARM::fixup_t2_movw_lo16: | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 710 | // Instruction size is 4 bytes. | 
|  | 711 | return 4; | 
|  | 712 | } | 
|  | 713 | } | 
|  | 714 |  | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 715 | void ARMAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 716 | unsigned DataSize, uint64_t Value, | 
|  | 717 | bool IsPCRel) const { | 
| Jim Grosbach | 9d6d77a | 2010-11-11 18:04:49 +0000 | [diff] [blame] | 718 | unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); | 
| Rafael Espindola | 5904e12 | 2014-03-29 06:26:49 +0000 | [diff] [blame] | 719 | Value = adjustFixupValue(Fixup, Value, IsPCRel, nullptr); | 
| Bill Wendling | f09c44c | 2010-12-07 23:11:00 +0000 | [diff] [blame] | 720 | if (!Value) return;           // Doesn't change encoding. | 
| Jim Grosbach | 9098714 | 2010-11-09 01:37:15 +0000 | [diff] [blame] | 721 |  | 
| Bill Wendling | f09c44c | 2010-12-07 23:11:00 +0000 | [diff] [blame] | 722 | unsigned Offset = Fixup.getOffset(); | 
|  | 723 | assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); | 
|  | 724 |  | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 725 | // Used to point to big endian bytes. | 
|  | 726 | unsigned FullSizeBytes; | 
|  | 727 | if (!IsLittleEndian) | 
|  | 728 | FullSizeBytes = getFixupKindContainerSizeBytes(Fixup.getKind()); | 
|  | 729 |  | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 730 | // For each byte of the fragment that the fixup touches, mask in the bits from | 
|  | 731 | // the fixup value. The Value has been "split up" into the appropriate | 
|  | 732 | // bitfields above. | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 733 | for (unsigned i = 0; i != NumBytes; ++i) { | 
|  | 734 | unsigned Idx = IsLittleEndian ? i : (FullSizeBytes - 1 - i); | 
|  | 735 | Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff); | 
|  | 736 | } | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 737 | } | 
| Bill Wendling | 721724e | 2010-12-07 23:05:20 +0000 | [diff] [blame] | 738 |  | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 739 | namespace { | 
|  | 740 |  | 
|  | 741 | // FIXME: This should be in a separate file. | 
|  | 742 | // ELF is an ELF of course... | 
|  | 743 | class ELFARMAsmBackend : public ARMAsmBackend { | 
|  | 744 | public: | 
|  | 745 | uint8_t OSABI; | 
|  | 746 | ELFARMAsmBackend(const Target &T, const StringRef TT, | 
| Christian Pirker | 6d301b8 | 2014-03-31 16:06:39 +0000 | [diff] [blame] | 747 | uint8_t OSABI, bool IsLittle) | 
|  | 748 | : ARMAsmBackend(T, TT, IsLittle), OSABI(OSABI) { } | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 749 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 750 | MCObjectWriter *createObjectWriter(raw_ostream &OS) const override { | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 751 | return createARMELFObjectWriter(OS, OSABI, isLittle()); | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 752 | } | 
|  | 753 | }; | 
|  | 754 |  | 
|  | 755 | // FIXME: This should be in a separate file. | 
|  | 756 | class DarwinARMAsmBackend : public ARMAsmBackend { | 
|  | 757 | public: | 
| Charles Davis | 8bdfafd | 2013-09-01 04:28:48 +0000 | [diff] [blame] | 758 | const MachO::CPUSubTypeARM Subtype; | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 759 | DarwinARMAsmBackend(const Target &T, const StringRef TT, | 
| Charles Davis | 8bdfafd | 2013-09-01 04:28:48 +0000 | [diff] [blame] | 760 | MachO::CPUSubTypeARM st) | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 761 | : ARMAsmBackend(T, TT, /* IsLittleEndian */ true), Subtype(st) { | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 762 | HasDataInCodeSupport = true; | 
|  | 763 | } | 
|  | 764 |  | 
| Craig Topper | ca7e3e5 | 2014-03-10 03:19:03 +0000 | [diff] [blame] | 765 | MCObjectWriter *createObjectWriter(raw_ostream &OS) const override { | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 766 | return createARMMachObjectWriter(OS, /*Is64Bit=*/false, | 
| Charles Davis | 8bdfafd | 2013-09-01 04:28:48 +0000 | [diff] [blame] | 767 | MachO::CPU_TYPE_ARM, | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 768 | Subtype); | 
|  | 769 | } | 
| Benjamin Kramer | 07ea85a | 2012-11-24 14:36:43 +0000 | [diff] [blame] | 770 | }; | 
|  | 771 |  | 
| Jim Grosbach | 689651c | 2010-09-30 03:21:00 +0000 | [diff] [blame] | 772 | } // end anonymous namespace | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 773 |  | 
| Bill Wendling | 58e2d3d | 2013-09-09 02:37:14 +0000 | [diff] [blame] | 774 | MCAsmBackend *llvm::createARMAsmBackend(const Target &T, | 
|  | 775 | const MCRegisterInfo &MRI, | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 776 | StringRef TT, StringRef CPU, | 
|  | 777 | bool isLittle) { | 
| Owen Anderson | 975ddf8 | 2011-04-01 21:07:39 +0000 | [diff] [blame] | 778 | Triple TheTriple(TT); | 
| Daniel Dunbar | 2b9b0e3 | 2011-04-19 21:14:45 +0000 | [diff] [blame] | 779 |  | 
| Tim Northover | d6a729b | 2014-01-06 14:28:05 +0000 | [diff] [blame] | 780 | if (TheTriple.isOSBinFormatMachO()) { | 
| Charles Davis | 8bdfafd | 2013-09-01 04:28:48 +0000 | [diff] [blame] | 781 | MachO::CPUSubTypeARM CS = | 
|  | 782 | StringSwitch<MachO::CPUSubTypeARM>(TheTriple.getArchName()) | 
|  | 783 | .Cases("armv4t", "thumbv4t", MachO::CPU_SUBTYPE_ARM_V4T) | 
|  | 784 | .Cases("armv5e", "thumbv5e", MachO::CPU_SUBTYPE_ARM_V5TEJ) | 
|  | 785 | .Cases("armv6", "thumbv6", MachO::CPU_SUBTYPE_ARM_V6) | 
|  | 786 | .Cases("armv6m", "thumbv6m", MachO::CPU_SUBTYPE_ARM_V6M) | 
|  | 787 | .Cases("armv7em", "thumbv7em", MachO::CPU_SUBTYPE_ARM_V7EM) | 
| Charles Davis | 8bdfafd | 2013-09-01 04:28:48 +0000 | [diff] [blame] | 788 | .Cases("armv7k", "thumbv7k", MachO::CPU_SUBTYPE_ARM_V7K) | 
|  | 789 | .Cases("armv7m", "thumbv7m", MachO::CPU_SUBTYPE_ARM_V7M) | 
|  | 790 | .Cases("armv7s", "thumbv7s", MachO::CPU_SUBTYPE_ARM_V7S) | 
|  | 791 | .Default(MachO::CPU_SUBTYPE_ARM_V7); | 
| Quentin Colombet | 77ca8b8 | 2013-01-14 21:34:09 +0000 | [diff] [blame] | 792 |  | 
|  | 793 | return new DarwinARMAsmBackend(T, TT, CS); | 
| Owen Anderson | 975ddf8 | 2011-04-01 21:07:39 +0000 | [diff] [blame] | 794 | } | 
| Daniel Dunbar | 2b9b0e3 | 2011-04-19 21:14:45 +0000 | [diff] [blame] | 795 |  | 
| NAKAMURA Takumi | 4d5ee804 | 2013-06-11 10:01:42 +0000 | [diff] [blame] | 796 | #if 0 | 
|  | 797 | // FIXME: Introduce yet another checker but assert(0). | 
| NAKAMURA Takumi | 76380ab | 2013-06-11 06:52:43 +0000 | [diff] [blame] | 798 | if (TheTriple.isOSBinFormatCOFF()) | 
| NAKAMURA Takumi | 4d5ee804 | 2013-06-11 10:01:42 +0000 | [diff] [blame] | 799 | assert(0 && "Windows not supported on ARM"); | 
|  | 800 | #endif | 
| Daniel Dunbar | 2b9b0e3 | 2011-04-19 21:14:45 +0000 | [diff] [blame] | 801 |  | 
| Rafael Espindola | 1ad4095 | 2011-12-21 17:00:36 +0000 | [diff] [blame] | 802 | uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(Triple(TT).getOS()); | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 803 | return new ELFARMAsmBackend(T, TT, OSABI, isLittle); | 
| Jason W Kim | b321245 | 2010-09-30 02:17:26 +0000 | [diff] [blame] | 804 | } | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 805 |  | 
| Christian Pirker | dc9ff75 | 2014-04-01 15:19:30 +0000 | [diff] [blame] | 806 | MCAsmBackend *llvm::createARMLEAsmBackend(const Target &T, | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 807 | const MCRegisterInfo &MRI, | 
|  | 808 | StringRef TT, StringRef CPU) { | 
|  | 809 | return createARMAsmBackend(T, MRI, TT, CPU, true); | 
|  | 810 | } | 
|  | 811 |  | 
| Christian Pirker | dc9ff75 | 2014-04-01 15:19:30 +0000 | [diff] [blame] | 812 | MCAsmBackend *llvm::createARMBEAsmBackend(const Target &T, | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 813 | const MCRegisterInfo &MRI, | 
|  | 814 | StringRef TT, StringRef CPU) { | 
|  | 815 | return createARMAsmBackend(T, MRI, TT, CPU, false); | 
|  | 816 | } | 
|  | 817 |  | 
| Christian Pirker | dc9ff75 | 2014-04-01 15:19:30 +0000 | [diff] [blame] | 818 | MCAsmBackend *llvm::createThumbLEAsmBackend(const Target &T, | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 819 | const MCRegisterInfo &MRI, | 
|  | 820 | StringRef TT, StringRef CPU) { | 
|  | 821 | return createARMAsmBackend(T, MRI, TT, CPU, true); | 
|  | 822 | } | 
|  | 823 |  | 
| Christian Pirker | dc9ff75 | 2014-04-01 15:19:30 +0000 | [diff] [blame] | 824 | MCAsmBackend *llvm::createThumbBEAsmBackend(const Target &T, | 
| Christian Pirker | 2a11160 | 2014-03-28 14:35:30 +0000 | [diff] [blame] | 825 | const MCRegisterInfo &MRI, | 
|  | 826 | StringRef TT, StringRef CPU) { | 
|  | 827 | return createARMAsmBackend(T, MRI, TT, CPU, false); | 
|  | 828 | } | 
|  | 829 |  |