ARM BL/BLX instruction fixups should use relocations.
authorJim Grosbach <grosbach@apple.com>
Mon, 27 Feb 2012 21:36:23 +0000 (21:36 +0000)
committerJim Grosbach <grosbach@apple.com>
Mon, 27 Feb 2012 21:36:23 +0000 (21:36 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151571 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCAsmBackend.h
lib/MC/MCAssembler.cpp
lib/Target/ARM/ARMCodeEmitter.cpp
lib/Target/ARM/ARMInstrInfo.td
lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
lib/Target/ARM/MCTargetDesc/ARMFixupKinds.h
lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
test/MC/ARM/arm_fixups.s
test/MC/ARM/basic-arm-instructions.s

index 11a081b207c56fb6941c8f6eeb162a3d48ccd69b..641ded5ef07564af8745deeac33f5700ae9a4da4 100644 (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) {}
 
   /// @}
 
index c041f65640a43966ea50bb9855dbc84af579c2c3..a2aaf4e83537674d45ecd7d5aa37852fd57a8cbf 100644 (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;
 }
index 3064f5701fb84ce2ee9ec835f902abb7aa401aca..8b101e6c4fa98d3e7d4de223e4dff6afb68aff61 100644 (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)
index dae09c70dd446c3126d4ed9414bffae3b26b5b9b..1c2976d3543270dd56c84289d458ec5ea9a4f3a9 100644 (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";
 }
index 55ea023d97ffb59a3a6b2455d12b97f09098a41d..d3a3d3a3b03895bc5c42a67601e883522e5ae707 100644 (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;
index a6a67e4af360f93aa30c414633dd5a8f61d16d6a..5476a46b71a026eff18d5a5e45d2957413e95b89 100644 (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:
index a819361ad0c2acf976defa207d3b3e2b70a29dc4..182798630b5b4bad4e9076cb28d68e8d945a54a9 100644 (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,
 
index 3a3b1674c7eba8f8e691c03f1296ab39aa0648d3..4445dcd8ddb7614bf19a36d307cf1662659f26ab 100644 (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;
 }
index 96a11ebe07aeeb25b48f8df6488141a648b1ef19..faf73ac07db8a26552bac7261084c834c8180556 100644 (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);
index aba0cd824dbcc4d0cf6e7816924f54b30a3eb931..2f3474836bcecbec8dc69c1e289bbaf0c7a87d66 100644 (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)
index a51b00be5390205b8fb15af7b7a62a4d40e3ce9d..4ae1ac76f3300f3763d6f90516ae29aff47be026 100644 (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]