]> granicus.if.org Git - llvm/commitdiff
ARM: move some logic from processFixupValue to applyFixup.
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 23 Jun 2017 22:52:36 +0000 (22:52 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 23 Jun 2017 22:52:36 +0000 (22:52 +0000)
processFixupValue is called on every relaxation iteration. applyFixup
is only called once at the very end. applyFixup is then the correct
place to do last minute changes and value checks.

While here, do proper range checks again for fixup_arm_thumb_bl. We
used to do it, but dropped because of thumb2. We now do it again, but
use the thumb2 range.

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

18 files changed:
include/llvm/MC/MCAsmBackend.h
include/llvm/MC/MCAssembler.h
lib/MC/MCAssembler.cpp
lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp
lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp
lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h
lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
test/MC/ARM/thumb-branches.s

index a146a8240726da094253233c034834c10d948137..c1370cc76b76319de5fee152624697deb64b492e 100644 (file)
@@ -73,7 +73,8 @@ public:
   /// the offset specified by the fixup and following the fixup kind as
   /// appropriate. Errors (such as an out of range fixup value) should be
   /// reported via \p Ctx.
-  virtual void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  virtual void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                          const MCValue &Target, MutableArrayRef<char> Data,
                           uint64_t Value, bool IsPCRel,
                           MCContext &Ctx) const = 0;
 
index a7e37817db134fcb6a8b071d160eb1477cdd6bcd..4f1b5a8b3d72e3cee46432af102cb991d3763239 100644 (file)
@@ -195,8 +195,8 @@ private:
   /// finishLayout - Finalize a layout, including fragment lowering.
   void finishLayout(MCAsmLayout &Layout);
 
-  std::pair<uint64_t, bool> handleFixup(const MCAsmLayout &Layout,
-                                        MCFragment &F, const MCFixup &Fixup);
+  std::tuple<MCValue, uint64_t, bool>
+  handleFixup(const MCAsmLayout &Layout, MCFragment &F, const MCFixup &Fixup);
 
 public:
   /// Construct a new assembler instance.
index 758c4c708f3dc3bed3b9475a9c9c83f74eab311b..e9941d0b7bf409b6a2d1c6ecf30b48e97dba0364 100644 (file)
@@ -648,9 +648,9 @@ void MCAssembler::writeSectionData(const MCSection *Sec,
          Layout.getSectionAddressSize(Sec));
 }
 
-std::pair<uint64_t, bool> MCAssembler::handleFixup(const MCAsmLayout &Layout,
-                                                   MCFragment &F,
-                                                   const MCFixup &Fixup) {
+std::tuple<MCValue, uint64_t, bool>
+MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F,
+                         const MCFixup &Fixup) {
   // Evaluate the fixup.
   MCValue Target;
   uint64_t FixedValue;
@@ -663,7 +663,7 @@ std::pair<uint64_t, bool> MCAssembler::handleFixup(const MCAsmLayout &Layout,
     getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, IsPCRel,
                                  FixedValue);
   }
-  return std::make_pair(FixedValue, IsPCRel);
+  return std::make_tuple(Target, FixedValue, IsPCRel);
 }
 
 void MCAssembler::layout(MCAsmLayout &Layout) {
@@ -740,9 +740,11 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
       for (const MCFixup &Fixup : Fixups) {
         uint64_t FixedValue;
         bool IsPCRel;
-        std::tie(FixedValue, IsPCRel) = handleFixup(Layout, Frag, Fixup);
-        getBackend().applyFixup(Fixup, Contents, FixedValue, IsPCRel,
-                                getContext());
+        MCValue Target;
+        std::tie(Target, FixedValue, IsPCRel) =
+            handleFixup(Layout, Frag, Fixup);
+        getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue,
+                                IsPCRel, getContext());
       }
     }
   }
index 9676a1a20b0d082a0feb55d5992b96f0a5792642..95aeb3e0f595ac8287c7431b3eba7859a1f97100 100644 (file)
@@ -71,7 +71,8 @@ public:
     return Infos[Kind - FirstTargetFixupKind];
   }
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
 
   bool mayNeedRelaxation(const MCInst &Inst) const override;
@@ -260,7 +261,8 @@ unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) con
   }
 }
 
-void AArch64AsmBackend::applyFixup(const MCFixup &Fixup,
+void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                                   const MCValue &Target,
                                    MutableArrayRef<char> Data, uint64_t Value,
                                    bool IsPCRel, MCContext &Ctx) const {
   unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
index d4d845c5322d099677d9f92f8c9f6d4b27e66d2a..07e5f4d8fc6470a99ea0630320a7b9582dbfe2c0 100644 (file)
@@ -36,7 +36,8 @@ public:
                          const MCValue &Target, uint64_t &Value,
                          bool &IsResolved) override;
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
   bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
                             const MCRelaxableFragment *DF,
@@ -129,7 +130,8 @@ void AMDGPUAsmBackend::processFixupValue(const MCAssembler &Asm,
     Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
 }
 
-void AMDGPUAsmBackend::applyFixup(const MCFixup &Fixup,
+void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                                  const MCValue &Target,
                                   MutableArrayRef<char> Data, uint64_t Value,
                                   bool IsPCRel, MCContext &Ctx) const {
   if (!Value)
index e06f23a91f5de8ad7350f9e04e73cf7c9cdd847a..46fb6caa0d2678e0a44383f2b056893928954780 100644 (file)
@@ -358,11 +358,27 @@ static uint32_t joinHalfWords(uint32_t FirstHalf, uint32_t SecondHalf,
   return Value;
 }
 
-unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
+unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
+                                         const MCFixup &Fixup,
+                                         const MCValue &Target, uint64_t Value,
                                          bool IsPCRel, MCContext &Ctx,
                                          bool IsLittleEndian,
                                          bool IsResolved) const {
   unsigned Kind = Fixup.getKind();
+
+  // MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
+  // and .word relocations they put the Thumb bit into the addend if possible.
+  // Other relocation types don't want this bit though (branches couldn't encode
+  // it if it *was* present, and no other relocations exist) and it can
+  // interfere with checking valid expressions.
+  if (const MCSymbolRefExpr *A = Target.getSymA()) {
+    if (A->hasSubsectionsViaSymbols() && Asm.isThumbFunc(&A->getSymbol()) &&
+        (Kind == FK_Data_4 || Kind == ARM::fixup_arm_movw_lo16 ||
+         Kind == ARM::fixup_arm_movt_hi16 || Kind == ARM::fixup_t2_movw_lo16 ||
+         Kind == ARM::fixup_t2_movt_hi16))
+      Value |= 1;
+  }
+
   switch (Kind) {
   default:
     Ctx.reportError(Fixup.getLoc(), "bad relocation fixup type");
@@ -505,6 +521,13 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
     return swapHalfWords(out, IsLittleEndian);
   }
   case ARM::fixup_arm_thumb_bl: {
+    // FIXME: We get both thumb1 and thumb2 in here, so we can only check for
+    // the less strict thumb2 value.
+    if (!isInt<26>(Value - 4)) {
+      Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
+      return 0;
+    }
+
     // The value doesn't encode the low bit (always zero) and is offset by
     // four. The 32-bit immediate value is encoded as
     //   imm32 = SignExtend(S:I1:I2:imm10:imm11:0)
@@ -724,21 +747,6 @@ void ARMAsmBackend::processFixupValue(const MCAssembler &Asm,
   const MCSymbolRefExpr *A = Target.getSymA();
   const MCSymbol *Sym = A ? &A->getSymbol() : nullptr;
   const unsigned FixupKind = Fixup.getKind() ;
-  // MachO (the only user of "Value") tries to make .o files that look vaguely
-  // pre-linked, so for MOVW/MOVT and .word relocations they put the Thumb bit
-  // into the addend if possible. Other relocation types don't want this bit
-  // though (branches couldn't encode it if it *was* present, and no other
-  // relocations exist) and it can interfere with checking valid expressions.
-  if (FixupKind == FK_Data_4 ||
-      FixupKind == ARM::fixup_arm_movw_lo16 ||
-      FixupKind == ARM::fixup_arm_movt_hi16 ||
-      FixupKind == ARM::fixup_t2_movw_lo16 ||
-      FixupKind == ARM::fixup_t2_movt_hi16) {
-    if (Sym) {
-      if (Asm.isThumbFunc(Sym))
-        Value |= 1;
-    }
-  }
   if (IsResolved && (unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_bl) {
     assert(Sym && "How did we resolve this?");
 
@@ -747,7 +755,7 @@ void ARMAsmBackend::processFixupValue(const MCAssembler &Asm,
 
     // If the symbol is out of range, produce a relocation and hope the
     // linker can handle it. GNU AS produces an error in this case.
-    if (Sym->isExternal() || Value >= 0x400004)
+    if (Sym->isExternal())
       IsResolved = false;
   }
   // Create relocations for unconditional branches to function symbols with
@@ -876,11 +884,13 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
   }
 }
 
-void ARMAsmBackend::applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
-                               uint64_t Value, bool IsPCRel,
-                               MCContext &Ctx) const {
+void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                               const MCValue &Target,
+                               MutableArrayRef<char> Data, uint64_t Value,
+                               bool IsPCRel, MCContext &Ctx) const {
   unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
-  Value = adjustFixupValue(Fixup, Value, IsPCRel, Ctx, IsLittleEndian, true);
+  Value = adjustFixupValue(Asm, Fixup, Target, Value, IsPCRel, Ctx,
+                           IsLittleEndian, true);
   if (!Value)
     return; // Doesn't change encoding.
 
index cb5e6e2eaef548d0c34e86238e1d07bbab609177..54cb162ee11233898cca2f08a79c45ad8f92c10e 100644 (file)
@@ -45,11 +45,13 @@ public:
                          const MCValue &Target, uint64_t &Value,
                          bool &IsResolved) override;
 
-  unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, bool IsPCRel,
+  unsigned adjustFixupValue(const MCAssembler &Asm, const MCFixup &Fixup,
+                            const MCValue &Target, uint64_t Value, bool IsPCRel,
                             MCContext &Ctx, bool IsLittleEndian,
                             bool IsResolved) const;
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
 
   unsigned getRelaxedOpcode(unsigned Op) const;
index 2df25cce26355a63d019afc710106383a92cbff7..2595b06de2c05d082bee7abcaf728c334f56bced 100644 (file)
@@ -27,7 +27,8 @@ public:
     : MCAsmBackend(), IsLittleEndian(IsLittleEndian) {}
   ~BPFAsmBackend() override = default;
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
 
   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
@@ -61,9 +62,10 @@ bool BPFAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
   return true;
 }
 
-void BPFAsmBackend::applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
-                               uint64_t Value, bool IsPCRel,
-                               MCContext &Ctx) const {
+void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                               const MCValue &Target,
+                               MutableArrayRef<char> Data, uint64_t Value,
+                               bool IsPCRel, MCContext &Ctx) const {
   if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) {
     assert(Value == 0);
   } else if (Fixup.getKind() == FK_Data_4 || Fixup.getKind() == FK_Data_8) {
index 0e513cce3301854605224072e6a95e7148847a4a..7cbc7898002b4757592692b511189cf3c95a1c9c 100644 (file)
@@ -415,7 +415,8 @@ public:
   /// ApplyFixup - Apply the \arg Value for given \arg Fixup into the provided
   /// data fragment, at the offset specified by the fixup and following the
   /// fixup kind as appropriate.
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t FixupValue, bool IsPCRel,
                   MCContext &Ctx) const override {
 
index d038a8dcbb0bcba84604d8ca75d402258351f39c..2833b54e1291a4359dba7c729314b874f4ae5733 100644 (file)
@@ -49,7 +49,8 @@ public:
   LanaiAsmBackend(const Target &T, Triple::OSType OST)
       : MCAsmBackend(), OSType(OST) {}
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
 
   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
@@ -88,7 +89,8 @@ bool LanaiAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
   return true;
 }
 
-void LanaiAsmBackend::applyFixup(const MCFixup &Fixup,
+void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                                 const MCValue &Target,
                                  MutableArrayRef<char> Data, uint64_t Value,
                                  bool /*IsPCRel*/, MCContext & /*Ctx*/) const {
   MCFixupKind Kind = Fixup.getKind();
index 91f271435e2e44541f9343836c5368699663a709..f9374b5b1d66faef375524c3eb83e455db22741d 100644 (file)
@@ -235,7 +235,8 @@ static unsigned calculateMMLEIndex(unsigned i) {
 /// ApplyFixup - Apply the \p Value for given \p Fixup into the provided
 /// data fragment, at the offset specified by the fixup and following the
 /// fixup kind as appropriate.
-void MipsAsmBackend::applyFixup(const MCFixup &Fixup,
+void MipsAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                                const MCValue &Target,
                                 MutableArrayRef<char> Data, uint64_t Value,
                                 bool IsPCRel, MCContext &Ctx) const {
   MCFixupKind Kind = Fixup.getKind();
index 3563554b23911bb40bda4fda4c3ee40e4db66c64..a1068dccf6dab19eb3b1679cf5a22595b89f457b 100644 (file)
@@ -38,7 +38,8 @@ public:
 
   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
 
   Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
index 6d72f111b37e3572e1642f9f6197ebf1107e34fa..1d14f072f6993e5097efcdb612f3b9fd5e2efff1 100644 (file)
@@ -113,7 +113,8 @@ public:
     return (IsLittleEndian? InfosLE : InfosBE)[Kind - FirstTargetFixupKind];
   }
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override {
     Value = adjustFixupValue(Fixup.getKind(), Value);
     if (!Value) return;           // Doesn't change encoding.
index f90e78ea9ffb576da14cfc116352aa8a7c6e20e2..e4f145698f375400d6cc9eed27d7887176f2a679 100644 (file)
@@ -32,7 +32,8 @@ public:
       : MCAsmBackend(), OSABI(OSABI), Is64Bit(Is64Bit) {}
   ~RISCVAsmBackend() override {}
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
 
   MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override;
@@ -69,7 +70,8 @@ bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
   return true;
 }
 
-void RISCVAsmBackend::applyFixup(const MCFixup &Fixup,
+void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                                 const MCValue &Target,
                                  MutableArrayRef<char> Data, uint64_t Value,
                                  bool IsPCRel, MCContext &Ctx) const {
   return;
index 42a931fff7518ea0239d73c16be883f218ab8e51..05137fa4aadee13871a88132e2a1d86d65e0fa87 100644 (file)
@@ -273,7 +273,8 @@ namespace {
     ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) :
       SparcAsmBackend(T), OSType(OSType) { }
 
-    void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+    void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                    const MCValue &Target, MutableArrayRef<char> Data,
                     uint64_t Value, bool IsPCRel,
                     MCContext &Ctx) const override {
 
index 86144dbff88f2450c5719121a511afdad2d795ec..69e275ef20323594a723f82e70bbd2cd786c4df7 100644 (file)
@@ -50,7 +50,8 @@ public:
     return SystemZ::NumTargetFixupKinds;
   }
   const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override;
   bool mayNeedRelaxation(const MCInst &Inst) const override {
     return false;
@@ -89,7 +90,9 @@ SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
   return Infos[Kind - FirstTargetFixupKind];
 }
 
-void SystemZMCAsmBackend::applyFixup(const MCFixup &Fixup,
+void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm,
+                                     const MCFixup &Fixup,
+                                     const MCValue &Target,
                                      MutableArrayRef<char> Data, uint64_t Value,
                                      bool IsPCRel, MCContext &Ctx) const {
   MCFixupKind Kind = Fixup.getKind();
index f57ee5c24019345fad1f9850cba6f5210fb46aa9..47591a2890ed721a4b774e40494ce5849fee92a9 100644 (file)
@@ -108,7 +108,8 @@ public:
     return Infos[Kind - FirstTargetFixupKind];
   }
 
-  void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data,
+  void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
+                  const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsPCRel, MCContext &Ctx) const override {
     unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
 
index b4cdfa12a55689f59b614c8a51b581df561a76ac..977df4619c4dd5b033ced0a7aca9040a9ce7ee9d 100644 (file)
@@ -1,25 +1,43 @@
-@ RUN: llvm-mc < %s -triple thumbv5-linux-gnueabi -filetype=obj -o - \
-@ RUN:   | llvm-readobj -r | FileCheck %s
+@ RUN: not llvm-mc %s -triple thumbv5-linux-gnueabi -filetype=obj -o /dev/null 2>&1 | FileCheck %s
 
+        .code 16
 
         bl      end
-        .space 0x3fffff
+        .space 0x1ffffff
 end:
 
         bl      end2
-        .space 0x3fffff
+        .space 0x1ffffff
         .global end2
 end2:
 
         bl      end3
-        .space 0x400000
+        .space 0x2000000
         .global end3
 end3:
 
+// CHECK-NOT: error
+// CHECK: [[@LINE+1]]:{{[0-9]}}: error: Relocation out of range
         bl      end4
-        .space 0x400000
+// CHECK-NOT: error
+        .space 0x2000000
 end4:
 
-@ CHECK: 0x400003 R_ARM_THM_CALL end2 0x0
-@ CHECK: 0x800006 R_ARM_THM_CALL end3 0x0
-@ CHECK: 0xC0000A R_ARM_THM_CALL end4 0x0
+start1:
+        .space 0x1fffffc
+        bl start1
+
+        .global start2
+start2:
+        .space 0x1fffffc
+        bl start2
+
+        .global start3
+start3:
+        .space 0x1fffffd
+        bl start3
+
+start4:
+        .space 0x1fffffd
+// CHECK: [[@LINE+1]]:{{[0-9]}}: error: Relocation out of range
+        bl start4