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 -= 4;
+ // FALLTHROUGH
+ case ARM::fixup_t2_ldst_pcrel_12: {
+ // Offset by 4, adjusted by two due to the half-word ordering of thumb.
+ Value -= 4;
+ 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: {
// These values don't encode the low two bits since they're always zero.
// Offset by 8 just as above.
return 0xffffff & ((Value - 8) >> 2);
+ case ARM::fixup_t2_uncondbranch: {
+ Value = Value - 4;
+ Value >>= 1; // Low bit is not encoded.
+
+ uint32_t out = 0;
+ bool I = Value & 0x800000;
+ bool J1 = Value & 0x400000;
+ bool J2 = Value & 0x200000;
+ J1 ^= I;
+ J2 ^= I;
+
+ out |= I << 26; // S bit
+ out |= !J1 << 13; // J1 bit
+ out |= !J2 << 11; // J2 bit
+ out |= (Value & 0x1FF800) << 5; // imm6 field
+ out |= (Value & 0x0007FF); // imm11 field
+
+ uint64_t swapped = (out & 0xFFFF0000) >> 16;
+ swapped |= (out & 0x0000FFFF) << 16;
+ return swapped;
+ }
+ case ARM::fixup_t2_condbranch: {
+ Value = Value - 4;
+ Value >>= 1; // Low bit is not encoded.
+
+ uint64_t out = 0;
+ out |= (Value & 0x80000) << 7; // S bit
+ out |= (Value & 0x40000) >> 7; // J2 bit
+ out |= (Value & 0x20000) >> 4; // J1 bit
+ out |= (Value & 0x1F800) << 5; // imm6 field
+ out |= (Value & 0x007FF); // imm11 field
+
+ uint32_t swapped = (out & 0xFFFF0000) >> 16;
+ swapped |= (out & 0x0000FFFF) << 16;
+ return swapped;
+ }
case ARM::fixup_arm_thumb_bl: {
// The value doesn't encode the low bit (always zero) and is offset by
// four. The value is encoded into disjoint bit positions in the destination
// opcode. x = unchanged, I = immediate value bit, S = sign extension bit
- // xxxxxSIIIIIIIIII xxxxxIIIIIIIIIII
+ //
+ // BL: xxxxxSIIIIIIIIII xxxxxIIIIIIIIIII
+ //
// Note that the halfwords are stored high first, low second; so we need
// to transpose the fixup value here to map properly.
- // FIXME: Something isn't quite right with this. Some, but not all, BLX
- // instructions are getting the encoded value off by one.
- uint32_t Binary = 0x3fffff & ((Value - 4) >> 1);
- Binary = ((Binary & 0x7ff) << 16) | (Binary >> 11);
+ unsigned isNeg = (int64_t(Value) < 0) ? 1 : 0;
+ uint32_t Binary = 0;
+ Value = 0x3fffff & ((Value - 4) >> 1);
+ Binary = (Value & 0x7ff) << 16; // Low imm11 value.
+ Binary |= (Value & 0x1ffc00) >> 11; // High imm10 value.
+ Binary |= isNeg << 10; // Sign bit.
+ return Binary;
+ }
+ case ARM::fixup_arm_thumb_blx: {
+ // The value doesn't encode the low two bits (always zero) and is offset by
+ // four (see fixup_arm_thumb_cp). The value is encoded into disjoint bit
+ // positions in the destination opcode. x = unchanged, I = immediate value
+ // bit, S = sign extension bit, 0 = zero.
+ //
+ // BLX: xxxxxSIIIIIIIIII xxxxxIIIIIIIIII0
+ //
+ // Note that the halfwords are stored high first, low second; so we need
+ // to transpose the fixup value here to map properly.
+ unsigned isNeg = (int64_t(Value) < 0) ? 1 : 0;
+ uint32_t Binary = 0;
+ Value = 0xfffff & ((Value - 2) >> 2);
+ Binary = (Value & 0x3ff) << 17; // Low imm10L value.
+ Binary |= (Value & 0xffc00) >> 10; // High imm10H value.
+ Binary |= isNeg << 10; // Sign bit.
return Binary;
}
case ARM::fixup_arm_thumb_cp:
// 'off by 4' is implicitly handled by the half-word ordering of the
// Thumb encoding, so we only need to adjust by 2 here.
return ((Value - 2) >> 2) & 0xff;
+ case ARM::fixup_arm_thumb_cb: {
+ // Offset by 4 and don't encode the lower bit, which is always 0.
+ uint32_t Binary = (Value - 4) >> 1;
+ return ((Binary & 0x20) << 9) | ((Binary & 0x1f) << 3);
+ }
+ case ARM::fixup_arm_thumb_br:
+ // Offset by 4 and don't encode the lower bit, which is always 0.
+ return ((Value - 4) >> 1) & 0x7ff;
+ case ARM::fixup_arm_thumb_bcc:
+ // Offset by 4 and don't encode the lower bit, which is always 0.
+ return ((Value - 4) >> 1) & 0xff;
case ARM::fixup_arm_pcrel_10:
- Value = Value - 6; // ARM fixups offset by an additional word and don't
+ Value = Value - 4; // ARM fixups offset by an additional word and don't
// need to adjust for the half-word ordering.
// Fall through.
case ARM::fixup_t2_pcrel_10: {
// Offset by 4, adjusted by two due to the half-word ordering of thumb.
- Value = Value - 2;
+ Value = Value - 4;
bool isAdd = true;
if ((int64_t)Value < 0) {
Value = -Value;
// Same addressing mode as fixup_arm_pcrel_10,
// but with 16-bit halfwords swapped.
if (Kind == ARM::fixup_t2_pcrel_10) {
- uint64_t swapped = (Value & 0xFFFF0000) >> 16;
+ uint32_t swapped = (Value & 0xFFFF0000) >> 16;
swapped |= (Value & 0x0000FFFF) << 16;
return swapped;
}
default:
llvm_unreachable("Unknown fixup kind!");
+ case ARM::fixup_arm_thumb_bcc:
case ARM::fixup_arm_thumb_cp:
return 1;
+ case ARM::fixup_arm_thumb_br:
+ case ARM::fixup_arm_thumb_cb:
+ return 2;
+
case ARM::fixup_arm_ldst_pcrel_12:
case ARM::fixup_arm_pcrel_10:
case ARM::fixup_arm_adr_pcrel_12:
return 3;
case FK_Data_4:
+ case ARM::fixup_t2_ldst_pcrel_12:
+ case ARM::fixup_t2_condbranch:
+ case ARM::fixup_t2_uncondbranch:
case ARM::fixup_t2_pcrel_10:
case ARM::fixup_arm_thumb_bl:
+ case ARM::fixup_arm_thumb_blx:
return 4;
}
}