ARM BL/BLX instruction fixups should use relocations.

We on the linker to resolve calls to the appropriate BL/BLX instruction
to make interworking function correctly. It uses the symbol in the
relocation to do that, so we need to be careful about being too clever.

To enable this for ARM mode, split the BL/BLX fixup kind off from the
unconditional-branch fixups.

rdar://10927209

llvm-svn: 151571
This commit is contained in:
Jim Grosbach 2012-02-27 21:36:23 +00:00
parent 20ba865302
commit 02bf78f5ca
11 changed files with 57 additions and 20 deletions

View File

@ -92,11 +92,13 @@ public:
virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const;
/// processFixupValue - Target hook to adjust the literal value of a fixup
/// if necessary. The default does nothing.
/// if necessary. IsResolved signals whether the caller believes a relocation
/// is needed; the target can modify the value. The default does nothing.
virtual void processFixupValue(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
MCValue &Target, uint64_t &Value) {}
MCValue &Target, uint64_t &Value,
bool &IsResolved) {}
/// @}

View File

@ -299,8 +299,10 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout,
Value -= Offset;
}
// Let the backend adjust the fixup value if necessary.
Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value);
// Let the backend adjust the fixup value if necessary, including whether
// we need a relocation.
Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value,
IsResolved);
return IsResolved;
}

View File

@ -189,6 +189,8 @@ namespace {
unsigned Op) const { return 0; }
unsigned getARMBranchTargetOpValue(const MachineInstr &MI, unsigned Op)
const { return 0; }
unsigned getARMBLTargetOpValue(const MachineInstr &MI, unsigned Op)
const { return 0; }
unsigned getARMBLXTargetOpValue(const MachineInstr &MI, unsigned Op)
const { return 0; }
unsigned getCCOutOpValue(const MachineInstr &MI, unsigned Op)

View File

@ -349,13 +349,11 @@ def bltarget : Operand<i32> {
// Call target for ARM. Handles conditional/unconditional
// FIXME: rename bl_target to t2_bltarget?
def bl_target : Operand<i32> {
// Encoded the same as branch targets.
let EncoderMethod = "getARMBranchTargetOpValue";
let EncoderMethod = "getARMBLTargetOpValue";
let OperandType = "OPERAND_PCREL";
}
def blx_target : Operand<i32> {
// Encoded the same as branch targets.
let EncoderMethod = "getARMBLXTargetOpValue";
let OperandType = "OPERAND_PCREL";
}

View File

@ -78,6 +78,8 @@ public:
{ "fixup_t2_condbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_t2_uncondbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_arm_thumb_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_arm_bl", 0, 24, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_arm_blx", 0, 24, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_arm_thumb_bl", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_arm_thumb_blx", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_arm_thumb_cb", 0, 16, MCFixupKindInfo::FKF_IsPCRel },
@ -106,18 +108,28 @@ public:
/// if necessary.
void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
MCValue &Target, uint64_t &Value) {
MCValue &Target, uint64_t &Value,
bool &IsResolved) {
const MCSymbolRefExpr *A = Target.getSymA();
// Some fixups to thumb function symbols need the low bit (thumb bit)
// twiddled.
if ((unsigned)Fixup.getKind() != ARM::fixup_arm_ldst_pcrel_12 &&
(unsigned)Fixup.getKind() != ARM::fixup_t2_ldst_pcrel_12 &&
(unsigned)Fixup.getKind() != ARM::fixup_arm_thumb_cp) {
if (const MCSymbolRefExpr *A = Target.getSymA()) {
if (A) {
const MCSymbol &Sym = A->getSymbol().AliasedSymbol();
if (Asm.isThumbFunc(&Sym))
Value |= 1;
}
}
// We must always generate a relocation for BL/BLX instructions if we have
// a symbol to reference, as the linker relies on knowing the destination
// symbol's thumb-ness to get interworking right.
if (A && ((unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_blx ||
(unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_bl ||
(unsigned)Fixup.getKind() == ARM::fixup_arm_blx ||
(unsigned)Fixup.getKind() == ARM::fixup_arm_bl))
IsResolved = false;
}
bool mayNeedRelaxation(const MCInst &Inst) const;
@ -343,6 +355,8 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
case ARM::fixup_arm_condbranch:
case ARM::fixup_arm_uncondbranch:
case ARM::fixup_arm_bl:
case ARM::fixup_arm_blx:
// 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);
@ -552,6 +566,8 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
case ARM::fixup_arm_ldst_pcrel_12:
case ARM::fixup_arm_pcrel_10:
case ARM::fixup_arm_adr_pcrel_12:
case ARM::fixup_arm_bl:
case ARM::fixup_arm_blx:
case ARM::fixup_arm_condbranch:
case ARM::fixup_arm_uncondbranch:
return 3;

View File

@ -177,6 +177,8 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
break;
}
break;
case ARM::fixup_arm_bl:
case ARM::fixup_arm_blx:
case ARM::fixup_arm_uncondbranch:
switch (Modifier) {
case MCSymbolRefExpr::VK_ARM_PLT:

View File

@ -59,6 +59,12 @@ enum Fixups {
// fixup_arm_thumb_br - 12-bit fixup for Thumb B instructions.
fixup_arm_thumb_br,
// fixup_arm_bl - Fixup for ARM BL instructions.
fixup_arm_bl,
// fixup_arm_blx - Fixup for ARM BLX instructions.
fixup_arm_blx,
// fixup_arm_thumb_bl - Fixup for Thumb BL instructions.
fixup_arm_thumb_bl,

View File

@ -118,8 +118,10 @@ public:
/// branch target.
uint32_t getARMBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const;
uint32_t getARMBLTargetOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const;
uint32_t getARMBLXTargetOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const;
SmallVectorImpl<MCFixup> &Fixups) const;
/// getAdrLabelOpValue - Return encoding info for 12-bit immediate
/// ADR label target.
@ -591,17 +593,22 @@ getARMBranchTargetOpValue(const MCInst &MI, unsigned OpIdx,
return MO.getImm() >> 2;
}
uint32_t ARMMCCodeEmitter::
getARMBLTargetOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const {
const MCOperand MO = MI.getOperand(OpIdx);
if (MO.isExpr())
return ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_arm_bl, Fixups);
return MO.getImm() >> 2;
}
uint32_t ARMMCCodeEmitter::
getARMBLXTargetOpValue(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups) const {
const MCOperand MO = MI.getOperand(OpIdx);
if (MO.isExpr()) {
if (HasConditionalBranch(MI))
return ::getBranchTargetOpValue(MI, OpIdx,
ARM::fixup_arm_condbranch, Fixups);
return ::getBranchTargetOpValue(MI, OpIdx,
ARM::fixup_arm_uncondbranch, Fixups);
}
if (MO.isExpr())
return ::getBranchTargetOpValue(MI, OpIdx, ARM::fixup_arm_blx, Fixups);
return MO.getImm() >> 1;
}

View File

@ -82,6 +82,8 @@ static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
case ARM::fixup_arm_adr_pcrel_12:
case ARM::fixup_arm_condbranch:
case ARM::fixup_arm_uncondbranch:
case ARM::fixup_arm_bl:
case ARM::fixup_arm_blx:
RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
// Report as 'long', even though that is not quite accurate.
Log2Size = llvm::Log2_32(4);

View File

@ -3,7 +3,7 @@
bl _printf
@ CHECK: bl _printf @ encoding: [A,A,A,0xeb]
@ CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_uncondbranch
@ CHECK: @ fixup A - offset: 0, value: _printf, kind: fixup_arm_bl
mov r9, :lower16:(_foo)
movw r9, :lower16:(_foo)

View File

@ -388,9 +388,9 @@ Lforward:
blx #16212288
@ CHECK: bl _bar @ encoding: [A,A,A,0xeb]
@ CHECK: @ fixup A - offset: 0, value: _bar, kind: fixup_arm_uncondbranch
@ CHECK: @ fixup A - offset: 0, value: _bar, kind: fixup_arm_bl
@ CHECK: blx _bar @ encoding: [A,A,A,0xfa]
@ fixup A - offset: 0, value: _bar, kind: fixup_arm_uncondbranch
@ fixup A - offset: 0, value: _bar, kind: fixup_arm_blx
@ CHECK: blls #28634268 @ encoding: [0x27,0x3b,0x6d,0x9b]
@ CHECK: blx #32424576 @ encoding: [0xa0,0xb0,0x7b,0xfa]
@ CHECK: blx #16212288 @ encoding: [0x50,0xd8,0x3d,0xfa]