diff --git a/lib/Target/ARM/ARMAsmBackend.cpp b/lib/Target/ARM/ARMAsmBackend.cpp index e2a23acd0ce..0f96d6120df 100644 --- a/lib/Target/ARM/ARMAsmBackend.cpp +++ b/lib/Target/ARM/ARMAsmBackend.cpp @@ -98,16 +98,28 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { Value = (Hi4 << 16) | (Lo12); return Value; } - case ARM::fixup_arm_ldst_pcrel_12: { - bool isAdd = true; + case ARM::fixup_arm_ldst_pcrel_12: // ARM PC-relative values are offset by 8. - Value -= 8; + Value -= 6; + case ARM::fixup_t2_ldst_pcrel_12: { + // Offset by 4, adjusted by two due to the half-word ordering of thumb. + Value -= 2; + bool isAdd = true; if ((int64_t)Value < 0) { Value = -Value; isAdd = false; } assert ((Value < 4096) && "Out of range pc-relative fixup value!"); Value |= isAdd << 23; + + // Same addressing mode as fixup_arm_pcrel_10, + // but with 16-bit halfwords swapped. + if (Kind == ARM::fixup_t2_ldst_pcrel_12) { + uint64_t swapped = (Value & 0xFFFF0000) >> 16; + swapped |= (Value & 0x0000FFFF) << 16; + return swapped; + } + return Value; } case ARM::fixup_arm_adr_pcrel_12: { @@ -128,7 +140,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { // Offset by 8 just as above. return 0xffffff & ((Value - 8) >> 2); case ARM::fixup_t2_branch: { - Value = Value - 6; + Value = Value - 8; Value >>= 1; // Low bit is not encoded. uint64_t out = 0; @@ -310,6 +322,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) { return 3; case FK_Data_4: + case ARM::fixup_t2_ldst_pcrel_12: case ARM::fixup_t2_branch: case ARM::fixup_t2_pcrel_10: case ARM::fixup_arm_thumb_bl: diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h index 997b22ef71d..8ee61d11aa8 100644 --- a/lib/Target/ARM/ARMFixupKinds.h +++ b/lib/Target/ARM/ARMFixupKinds.h @@ -18,6 +18,11 @@ enum Fixups { // fixup_arm_ldst_pcrel_12 - 12-bit PC relative relocation for symbol // addresses fixup_arm_ldst_pcrel_12 = FirstTargetFixupKind, + + // fixup_t2_ldst_pcrel_12 - Equivalent to fixup_arm_ldst_pcrel_12, with + // the 16-bit halfwords reordered. + fixup_t2_ldst_pcrel_12, + // fixup_arm_pcrel_10 - 10-bit PC relative relocation for symbol addresses // used in VFP instructions where the lower 2 bits are not encoded // (so it's encoded as an 8-bit immediate). diff --git a/lib/Target/ARM/ARMMCCodeEmitter.cpp b/lib/Target/ARM/ARMMCCodeEmitter.cpp index 8fbeb0e6e0d..9684fb1de84 100644 --- a/lib/Target/ARM/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/ARMMCCodeEmitter.cpp @@ -47,6 +47,7 @@ public: const static MCFixupKindInfo Infos[] = { // name off bits flags { "fixup_arm_ldst_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_t2_ldst_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_arm_pcrel_10", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_t2_pcrel_10", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_arm_adr_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, @@ -508,7 +509,12 @@ getAddrModeImm12OpValue(const MCInst &MI, unsigned OpIdx, else Expr = MO2.getExpr(); - MCFixupKind Kind = MCFixupKind(ARM::fixup_arm_ldst_pcrel_12); + const ARMSubtarget &Subtarget = TM.getSubtarget(); + MCFixupKind Kind; + if (Subtarget.isThumb2()) + Kind = MCFixupKind(ARM::fixup_t2_ldst_pcrel_12); + else + Kind = MCFixupKind(ARM::fixup_arm_ldst_pcrel_12); Fixups.push_back(MCFixup::Create(0, Expr, Kind)); ++MCNumCPRelocations;