diff --git a/include/llvm/MC/MCAsmBackend.h b/include/llvm/MC/MCAsmBackend.h index 11a081b207c..641ded5ef07 100644 --- a/include/llvm/MC/MCAsmBackend.h +++ b/include/llvm/MC/MCAsmBackend.h @@ -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) {} /// @} diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index c041f65640a..a2aaf4e8353 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -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; } diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index 3064f5701fb..8b101e6c4fa 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -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) diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index dae09c70dd4..1c2976d3543 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -349,13 +349,11 @@ def bltarget : Operand { // Call target for ARM. Handles conditional/unconditional // FIXME: rename bl_target to t2_bltarget? def bl_target : Operand { - // Encoded the same as branch targets. - let EncoderMethod = "getARMBranchTargetOpValue"; + let EncoderMethod = "getARMBLTargetOpValue"; let OperandType = "OPERAND_PCREL"; } def blx_target : Operand { - // Encoded the same as branch targets. let EncoderMethod = "getARMBLXTargetOpValue"; let OperandType = "OPERAND_PCREL"; } diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp index 55ea023d97f..d3a3d3a3b03 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -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; diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp index a6a67e4af36..5476a46b71a 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -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: diff --git a/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h b/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h index a819361ad0c..182798630b5 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h +++ b/lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h @@ -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, diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp index 3a3b1674c7e..4445dcd8ddb 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -118,8 +118,10 @@ public: /// branch target. uint32_t getARMBranchTargetOpValue(const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups) const; + uint32_t getARMBLTargetOpValue(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups) const; uint32_t getARMBLXTargetOpValue(const MCInst &MI, unsigned OpIdx, - SmallVectorImpl &Fixups) const; + SmallVectorImpl &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 &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 &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; } diff --git a/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp index 96a11ebe07a..faf73ac07db 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp @@ -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); diff --git a/test/MC/ARM/arm_fixups.s b/test/MC/ARM/arm_fixups.s index aba0cd824db..2f3474836bc 100644 --- a/test/MC/ARM/arm_fixups.s +++ b/test/MC/ARM/arm_fixups.s @@ -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) diff --git a/test/MC/ARM/basic-arm-instructions.s b/test/MC/ARM/basic-arm-instructions.s index a51b00be539..4ae1ac76f33 100644 --- a/test/MC/ARM/basic-arm-instructions.s +++ b/test/MC/ARM/basic-arm-instructions.s @@ -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]