[lld] 62c6057 - [lld][ARM] support absolute thunks for Armv4T Thumb and interworking

Ties Stuij via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 21 03:06:19 PST 2022


Author: Ties Stuij
Date: 2022-12-21T11:04:32Z
New Revision: 62c605771a30962e32c7e14d8911c3e5e829b38d

URL: https://github.com/llvm/llvm-project/commit/62c605771a30962e32c7e14d8911c3e5e829b38d
DIFF: https://github.com/llvm/llvm-project/commit/62c605771a30962e32c7e14d8911c3e5e829b38d.diff

LOG: [lld][ARM] support absolute thunks for Armv4T Thumb and interworking

changes:
- BLX: The Arm architecture versions that support the branch and link
  instruction (BLX), can rewrite BLs in place when a state change from Arm<->Thumb
  is required. Armv4T does not have BLX and so needs thunks for state changes.
- v4T Thumb long branches needed their own thunk. We could have used the v6M
  implementation, but v6M doesn't have Arm state and must resolve to rather
  inefficient stack reshuffling. We also can't reuse v7 thumb thunks as they use
  MOVV/MOVT, which wasn't available yet for v4T.
- Remove the `lack of BLX' warning. LLVM only supports Arm Architecture versions
  upwards of v4, which we now all support in LLD.
- renamed existing thunks to better reflect their use:
  ARMV5ABSLongThunk -> ARMV5LongLdrPcThunk,
  ARMV5PILongThunk -> ARMV4PILongThunk
- removed isCompatibleWith method from ARMV5ABSLongThunk and ARMV5PILongThunk,
  as they were identical to the ARMThunk parent class implementation.

Support for (efficient) position independent thunks for v4T will be added in a
follow-up patch, including possible related thunk renaming and code comment
cleanup.

Reviewed By: MaskRay, peter.smith

Differential Revision: https://reviews.llvm.org/D139888

Added: 
    lld/test/ELF/arm-bl-v4t.s
    lld/test/ELF/arm-bx-v4t.s

Modified: 
    lld/ELF/Arch/ARM.cpp
    lld/ELF/Driver.cpp
    lld/ELF/Thunks.cpp
    lld/test/ELF/arm-bl-v6.s
    lld/test/ELF/arm-blx.s
    lld/test/ELF/arm-thumb-interwork-thunk-v5.s
    lld/test/ELF/arm-thunk-multipass-plt.s

Removed: 
    lld/test/ELF/arm-blx-v4t.s


################################################################################
diff  --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index ff692edf2af5..24d78ebf5820 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -314,7 +314,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
     [[fallthrough]];
   case R_ARM_CALL: {
     uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA();
-    return !inBranchRange(type, branchAddr, dst + a);
+    return !inBranchRange(type, branchAddr, dst + a) ||
+        (!config->armHasBlx && (s.getVA() & 1));
   }
   case R_ARM_THM_JUMP19:
   case R_ARM_THM_JUMP24:
@@ -325,7 +326,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
     [[fallthrough]];
   case R_ARM_THM_CALL: {
     uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA();
-    return !inBranchRange(type, branchAddr, dst + a);
+    return !inBranchRange(type, branchAddr, dst + a) ||
+        (!config->armHasBlx && (s.getVA() & 1) == 0);;
   }
   }
   return false;

diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index a051228518cb..233b334d3a38 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2786,15 +2786,6 @@ void LinkerDriver::link(opt::InputArgList &args) {
 
   config->imageBase = getImageBase(args);
 
-  if (config->emachine == EM_ARM) {
-    // FIXME: These warnings can be removed when lld only uses these features
-    // when the input objects have been compiled with an architecture that
-    // supports them.
-    if (config->armHasBlx == false)
-      warn("lld uses blx instruction, no object with architecture supporting "
-           "feature detected");
-  }
-
   // This adds a .comment section containing a version string.
   if (!config->relocatable)
     ctx.inputSections.push_back(createCommentSection());

diff  --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index fc987dee481a..d805dee9ac4b 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -161,37 +161,67 @@ class ThumbV7PILongThunk final : public ThumbThunk {
   void addSymbols(ThunkSection &isec) override;
 };
 
-// Implementations of Thunks for older Arm architectures that do not support
-// the movt/movw instructions. These thunks require at least Architecture v5
-// as used on processors such as the Arm926ej-s. There are no Thumb entry
-// points as there is no Thumb branch instruction on these architecture that
-// can result in a thunk
-class ARMV5ABSLongThunk final : public ARMThunk {
+// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
+class ThumbV6MABSLongThunk final : public ThumbThunk {
+public:
+  ThumbV6MABSLongThunk(Symbol &dest, int64_t addend)
+      : ThumbThunk(dest, addend) {}
+
+  uint32_t sizeLong() override { return 12; }
+  void writeLong(uint8_t *buf) override;
+  void addSymbols(ThunkSection &isec) override;
+};
+
+class ThumbV6MPILongThunk final : public ThumbThunk {
+public:
+  ThumbV6MPILongThunk(Symbol &dest, int64_t addend)
+      : ThumbThunk(dest, addend) {}
+
+  uint32_t sizeLong() override { return 16; }
+  void writeLong(uint8_t *buf) override;
+  void addSymbols(ThunkSection &isec) override;
+};
+
+// Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
+// v6 support BLX to which BL instructions can be rewritten inline. There are no
+// Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on
+// these architecture that can result in a thunk.
+
+// LDR on v5 and v6 can switch processor state, so for v5 and v6,
+// ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4
+// can also use this thunk, but only for Arm->Arm calls.
+class ARMV5LongLdrPcThunk final : public ARMThunk {
 public:
-  ARMV5ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
+  ARMV5LongLdrPcThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
 
   uint32_t sizeLong() override { return 8; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
-  bool isCompatibleWith(const InputSection &isec,
-                        const Relocation &rel) const override;
 };
 
-class ARMV5PILongThunk final : public ARMThunk {
+class ARMV4PILongThunk final : public ARMThunk {
 public:
-  ARMV5PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
+  ARMV4PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
 
   uint32_t sizeLong() override { return 16; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
-  bool isCompatibleWith(const InputSection &isec,
-                        const Relocation &rel) const override;
 };
 
-// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
-class ThumbV6MABSLongThunk final : public ThumbThunk {
+// Implementations of Thunks for v4. BLX is not supported, and loads
+// will not invoke Arm/Thumb state changes.
+class ARMV4ABSLongBXThunk final : public ARMThunk {
 public:
-  ThumbV6MABSLongThunk(Symbol &dest, int64_t addend)
+  ARMV4ABSLongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
+
+  uint32_t sizeLong() override { return 12; }
+  void writeLong(uint8_t *buf) override;
+  void addSymbols(ThunkSection &isec) override;
+};
+
+class ThumbV4ABSLongBXThunk final : public ThumbThunk {
+public:
+  ThumbV4ABSLongBXThunk(Symbol &dest, int64_t addend)
       : ThumbThunk(dest, addend) {}
 
   uint32_t sizeLong() override { return 12; }
@@ -199,9 +229,9 @@ class ThumbV6MABSLongThunk final : public ThumbThunk {
   void addSymbols(ThunkSection &isec) override;
 };
 
-class ThumbV6MPILongThunk final : public ThumbThunk {
+class ThumbV4ABSLongThunk final : public ThumbThunk {
 public:
-  ThumbV6MPILongThunk(Symbol &dest, int64_t addend)
+  ThumbV4ABSLongThunk(Symbol &dest, int64_t addend)
       : ThumbThunk(dest, addend) {}
 
   uint32_t sizeLong() override { return 16; }
@@ -504,6 +534,10 @@ void ARMThunk::writeTo(uint8_t *buf) {
 
 bool ARMThunk::isCompatibleWith(const InputSection &isec,
                                 const Relocation &rel) const {
+  // v4T does not have BLX, so also deny R_ARM_THM_CALL
+  if (!config->armHasBlx && rel.type == R_ARM_THM_CALL)
+    return false;
+
   // Thumb branch relocations can't use BLX
   return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
 }
@@ -542,6 +576,10 @@ void ThumbThunk::writeTo(uint8_t *buf) {
 
 bool ThumbThunk::isCompatibleWith(const InputSection &isec,
                                   const Relocation &rel) const {
+  // v4T does not have BLX, so also deny R_ARM_CALL
+  if (!config->armHasBlx && rel.type == R_ARM_CALL)
+    return false;
+
   // ARM branch relocations can't use BLX
   return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
 }
@@ -624,54 +662,6 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
   addSymbol("$t", STT_NOTYPE, 0, isec);
 }
 
-void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
-  const uint8_t data[] = {
-      0x04, 0xf0, 0x1f, 0xe5, //     ldr pc, [pc,#-4] ; L1
-      0x00, 0x00, 0x00, 0x00, // L1: .word S
-  };
-  memcpy(buf, data, sizeof(data));
-  target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
-}
-
-void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
-  addSymbol(saver().save("__ARMv5ABSLongThunk_" + destination.getName()),
-            STT_FUNC, 0, isec);
-  addSymbol("$a", STT_NOTYPE, 0, isec);
-  addSymbol("$d", STT_NOTYPE, 4, isec);
-}
-
-bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec,
-                                         const Relocation &rel) const {
-  // Thumb branch relocations can't use BLX
-  return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
-}
-
-void ARMV5PILongThunk::writeLong(uint8_t *buf) {
-  const uint8_t data[] = {
-      0x04, 0xc0, 0x9f, 0xe5, // P:  ldr ip, [pc,#4] ; L2
-      0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
-      0x1c, 0xff, 0x2f, 0xe1, //     bx ip
-      0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
-  };
-  uint64_t s = getARMThunkDestVA(destination);
-  uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
-  memcpy(buf, data, sizeof(data));
-  target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
-}
-
-void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
-  addSymbol(saver().save("__ARMV5PILongThunk_" + destination.getName()),
-            STT_FUNC, 0, isec);
-  addSymbol("$a", STT_NOTYPE, 0, isec);
-  addSymbol("$d", STT_NOTYPE, 12, isec);
-}
-
-bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec,
-                                        const Relocation &rel) const {
-  // Thumb branch relocations can't use BLX
-  return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
-}
-
 void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
   // Most Thumb instructions cannot access the high registers r8 - r15. As the
   // only register we can corrupt is r12 we must instead spill a low register
@@ -722,6 +712,98 @@ void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
   addSymbol("$d", STT_NOTYPE, 12, isec);
 }
 
+void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
+  const uint8_t data[] = {
+      0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
+      0x00, 0x00, 0x00, 0x00, // L1: .word S
+  };
+  memcpy(buf, data, sizeof(data));
+  target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
+}
+
+void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
+  addSymbol(saver().save("__ARMv5LongLdrPcThunk_" + destination.getName()),
+            STT_FUNC, 0, isec);
+  addSymbol("$a", STT_NOTYPE, 0, isec);
+  addSymbol("$d", STT_NOTYPE, 4, isec);
+}
+
+void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
+  const uint8_t data[] = {
+      0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1
+      0x1c, 0xff, 0x2f, 0xe1, // bx r12
+      0x00, 0x00, 0x00, 0x00, // L1: .word S
+  };
+  memcpy(buf, data, sizeof(data));
+  target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
+}
+
+void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
+  addSymbol(saver().save("__ARMv4ABSLongBXThunk_" + destination.getName()),
+            STT_FUNC, 0, isec);
+  addSymbol("$a", STT_NOTYPE, 0, isec);
+  addSymbol("$d", STT_NOTYPE, 8, isec);
+}
+
+void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
+  const uint8_t data[] = {
+      0x78, 0x47,             // bx pc
+      0xfd, 0xe7,             // b #-6 ; Arm recommended sequence to follow bx pc
+      0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4] ; L1
+      0x00, 0x00, 0x00, 0x00, // L1: .word S
+  };
+  memcpy(buf, data, sizeof(data));
+  target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
+}
+
+void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
+  addSymbol(saver().save("__Thumbv4ABSLongBXThunk_" + destination.getName()),
+            STT_FUNC, 1, isec);
+  addSymbol("$t", STT_NOTYPE, 0, isec);
+  addSymbol("$a", STT_NOTYPE, 4, isec);
+  addSymbol("$d", STT_NOTYPE, 8, isec);
+}
+
+void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
+  const uint8_t data[] = {
+      0x78, 0x47,             // bx pc
+      0xfd, 0xe7,             // b #-6 ; Arm recommended sequence to follow bx pc
+      0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1
+      0x1c, 0xff, 0x2f, 0xe1, // bx r12
+      0x00, 0x00, 0x00, 0x00, // L1: .word S
+  };
+  memcpy(buf, data, sizeof(data));
+  target->relocateNoSym(buf + 12, R_ARM_ABS32, getARMThunkDestVA(destination));
+}
+
+void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
+  addSymbol(saver().save("__Thumbv4ABSLongThunk_" + destination.getName()),
+            STT_FUNC, 1, isec);
+  addSymbol("$t", STT_NOTYPE, 0, isec);
+  addSymbol("$a", STT_NOTYPE, 4, isec);
+  addSymbol("$d", STT_NOTYPE, 12, isec);
+}
+
+void ARMV4PILongThunk::writeLong(uint8_t *buf) {
+  const uint8_t data[] = {
+      0x04, 0xc0, 0x9f, 0xe5, // P:  ldr ip, [pc,#4] ; L2
+      0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
+      0x1c, 0xff, 0x2f, 0xe1, //     bx ip
+      0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
+  };
+  uint64_t s = getARMThunkDestVA(destination);
+  uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
+  memcpy(buf, data, sizeof(data));
+  target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
+}
+
+void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
+  addSymbol(saver().save("__ARMv4PILongThunk_" + destination.getName()),
+            STT_FUNC, 0, isec);
+  addSymbol("$a", STT_NOTYPE, 0, isec);
+  addSymbol("$d", STT_NOTYPE, 12, isec);
+}
+
 // Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
 void MipsThunk::writeTo(uint8_t *buf) {
   uint64_t s = destination.getVA();
@@ -1051,12 +1133,49 @@ static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
   return make<AArch64ABSLongThunk>(s, a);
 }
 
-// Creates a thunk for Thumb-ARM interworking.
-// Arm Architectures v5 and v6 do not support Thumb2 technology. This means
+// Creates a thunk for long branches or Thumb-ARM interworking.
+// Arm Architectures v4t does not support Thumb2 technology, and does not
+// support BLX or LDR Arm/Thumb state switching. This means that
+// - MOVT and MOVW instructions cannot be used.
+// - We can't rewrite BL in place to BLX. We will need thunks.
+//
+// TODO: Support PIC interworking thunks for V4T.
+// TODO: More efficient PIC non-interworking thunks for V4T.
+// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
+//       Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
+static Thunk *addThunkArmv4(RelType reloc, Symbol &s, int64_t a) {
+  bool thumb_target = s.getVA(a) & 1;
+
+  switch (reloc) {
+  case R_ARM_PC24:
+  case R_ARM_PLT32:
+  case R_ARM_JUMP24:
+  case R_ARM_CALL:
+    if (config->picThunk)
+      // can be used for both Arm->Arm and Arm->Thumb
+      return make<ARMV4PILongThunk>(s, a);
+    if (thumb_target)
+      return make<ARMV4ABSLongBXThunk>(s, a);
+    return make<ARMV5LongLdrPcThunk>(s, a);
+  case R_ARM_THM_CALL:
+    if (config->picThunk && !thumb_target)
+      fatal("PIC relocations across state change not supported for Armv4T");
+    if (config->picThunk && thumb_target)
+      return make<ThumbV6MPILongThunk>(s, a);
+    if (thumb_target)
+      return make<ThumbV4ABSLongThunk>(s, a);
+    return make<ThumbV4ABSLongBXThunk>(s, a);
+  }
+  fatal("relocation " + toString(reloc) + " to " + toString(s) +
+        " not supported for Armv4 or Armv4T target");
+}
+
+// Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
+// Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
 // - MOVT and MOVW instructions cannot be used
 // - Only Thumb relocation that can generate a Thunk is a BL, this can always
 //   be transformed into a BLX
-static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s, int64_t a) {
+static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) {
   switch (reloc) {
   case R_ARM_PC24:
   case R_ARM_PLT32:
@@ -1064,8 +1183,8 @@ static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s, int64_t a) {
   case R_ARM_CALL:
   case R_ARM_THM_CALL:
     if (config->picThunk)
-      return make<ARMV5PILongThunk>(s, a);
-    return make<ARMV5ABSLongThunk>(s, a);
+      return make<ARMV4PILongThunk>(s, a);
+    return make<ARMV5LongLdrPcThunk>(s, a);
   }
   fatal("relocation " + toString(reloc) + " to " + toString(s) +
         " not supported for Armv5 or Armv6 targets");
@@ -1108,9 +1227,11 @@ static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
   // of the input objects. InputFiles.cpp contains the mapping from ARM
   // architecture to flag.
   if (!config->armHasMovtMovw) {
-    if (!config->armJ1J2BranchEncoding)
-      return addThunkPreArmv7(reloc, s, a);
-    return addThunkV6M(reloc, s, a);
+    if (config->armJ1J2BranchEncoding)
+      return addThunkV6M(reloc, s, a);
+    if (config->armHasBlx)
+      return addThunkArmv5v6(reloc, s, a);
+    return addThunkArmv4(reloc, s, a);
   }
 
   switch (reloc) {

diff  --git a/lld/test/ELF/arm-bl-v4t.s b/lld/test/ELF/arm-bl-v4t.s
new file mode 100644
index 000000000000..691995029a46
--- /dev/null
+++ b/lld/test/ELF/arm-bl-v4t.s
@@ -0,0 +1,105 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv4t-none-linux-gnueabi %t/a.s -o %t/a.o
+// RUN: ld.lld %t/a.o --script %t/far.lds -o %t/a-far
+// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-far | FileCheck %s --check-prefixes=FAR
+// RUN: ld.lld %t/a.o --script %t/near.lds -o %t/a-near
+// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-near | FileCheck %s --check-prefixes=NEAR
+
+/// On Armv4T there is no blx instruction so long branch/exchange looks slightly
+/// 
diff erent.
+
+#--- a.s
+ .text
+ .syntax unified
+ .cpu    arm7tdmi
+
+ .section .low, "ax", %progbits
+ .arm
+ .globl _start
+ .type   _start,%function
+ .p2align       2
+_start:
+  bl target
+  bx lr
+
+ .thumb
+ .globl thumb_start
+ .type  thumb_start,%function
+ .p2align       2
+thumb_start:
+  bl thumb_target
+  bx lr
+
+// FAR-LABEL: <_start>:
+// FAR-NEXT:   1000000:      	bl	0x1000010 <__ARMv5LongLdrPcThunk_target> @ imm = #8
+// FAR-NEXT:                	bx	lr
+// FAR-EMPTY:
+// FAR-LABEL: <thumb_start>:
+// FAR-NEXT:   1000008:      	bl	0x1000018 <__Thumbv4ABSLongThunk_thumb_target> @ imm = #12
+// FAR-NEXT:                	bx	lr
+// FAR-NEXT:                	bmi	0xffffba                @ imm = #-88
+// FAR-EMPTY:
+// FAR-NEXT:  <__ARMv5LongLdrPcThunk_target>:
+// FAR-NEXT:   1000010:      	ldr	pc, [pc, #-4]           @ 0x1000014 <__ARMv5LongLdrPcThunk_target+0x4>
+// FAR-EMPTY: 
+// FAR-NEXT:  <$d>:
+// FAR-NEXT:   1000014: 00 00 00 06  	.word	0x06000000
+// FAR-EMPTY:
+// FAR-NEXT:  <__Thumbv4ABSLongThunk_thumb_target>:
+// FAR-NEXT:   1000018:      	bx	pc
+// FAR-NEXT:                	b	0x1000018 <__Thumbv4ABSLongThunk_thumb_target> @ imm = #-6
+// FAR-EMPTY:
+// FAR-NEXT:  <$a>:
+// FAR-NEXT:   100001c:      	ldr	r12, [pc]               @ 0x1000024 <__Thumbv4ABSLongThunk_thumb_target+0xc>
+// FAR-NEXT:                	bx	r12
+// FAR-EMPTY:
+// FAR-NEXT:  <$d>:
+// FAR-NEXT:   1000024: 05 00 00 06  	.word	0x06000005
+
+// NEAR-LABEL: <_start>:
+// NEAR-NEXT:  1000000:      	bl	0x100000c <thumb_start+0x4> @ imm = #4
+// NEAR-NEXT:               	bx	lr
+// NEAR-EMPTY:
+// NEAR-LABEL: <thumb_start>:
+// NEAR-NEXT:  1000008:      	bl	0x1000012 <thumb_target> @ imm = #6
+// NEAR-NEXT:               	bx	lr
+
+.section .high, "ax", %progbits
+ .arm
+ .globl target
+ .type target,%function
+target:
+  bx lr
+
+.thumb
+ .globl thumb_target
+ .type thumb_target,%function
+thumb_target:
+  bx lr
+
+// FAR-LABEL: <target>:
+// FAR-NEXT:   6000000:      	bx	lr
+// FAR-EMPTY:
+// FAR-LABEL: <thumb_target>:
+// FAR-NEXT:   6000004:      	bx	lr
+
+// NEAR-LABEL: <target>:
+// NEAR-LABEL:  100000e:      	bx	lr
+// NEAR-EMPTY:
+// NEAR-NEXT: <thumb_target>:
+// NEAR-NEXT:  1000012:      	bx	lr
+
+                                     
+#--- far.lds
+SECTIONS {
+  . = SIZEOF_HEADERS;
+  .low 0x01000000 : { *(.low) }
+  .high 0x06000000 : { *(.high) }
+}
+
+#--- near.lds
+SECTIONS {
+  . = SIZEOF_HEADERS;
+  .all 0x01000000 : { *(.low) *(.high) }
+}

diff  --git a/lld/test/ELF/arm-bl-v6.s b/lld/test/ELF/arm-bl-v6.s
index ffcc01222b17..375bc9bd7f53 100644
--- a/lld/test/ELF/arm-bl-v6.s
+++ b/lld/test/ELF/arm-bl-v6.s
@@ -38,13 +38,13 @@ thumbfunc:
  bl farthumbfunc
 
 // CHECK-THUMB1: <thumbfunc>:
-// CHECK-THUMB1-NEXT:    21008: f200 e800 	 	blx	0x22100c <__ARMv5ABSLongThunk_farthumbfunc>
+// CHECK-THUMB1-NEXT:    21008: f200 e800 	 	blx	0x22100c <__ARMv5LongLdrPcThunk_farthumbfunc>
 /// 6 Megabytes, enough to make farthumbfunc out of range of caller
 /// on a v6 Arm, but not on a v7 Arm.
 
  .section .text.3, "ax", %progbits
  .space 0x200000
-// CHECK-ARM2: <__ARMv5ABSLongThunk_farthumbfunc>:
+// CHECK-ARM2: <__ARMv5LongLdrPcThunk_farthumbfunc>:
 // CHECK-ARM2-NEXT:   22100c:   e51ff004        ldr     pc, [pc, #-4]
 // CHECK-ARM2: <$d>:
 // CHECK-ARM2-NEXT:   221010:   01 20 62 00     .word   0x00622001

diff  --git a/lld/test/ELF/arm-blx-v4t.s b/lld/test/ELF/arm-blx-v4t.s
deleted file mode 100644
index 6c2b69885a10..000000000000
--- a/lld/test/ELF/arm-blx-v4t.s
+++ /dev/null
@@ -1,27 +0,0 @@
-// REQUIRES: arm
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t
-// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s
-
-// On Arm v4t there is no blx instruction so all interworking must go via
-// a thunk. At present we don't support v4t so we give a warning for unsupported
-// features.
-
-// CHECK: warning: lld uses blx instruction, no object with architecture supporting feature detected
-
- .text
- .syntax unified
- .cpu   arm7tdmi
- .arm
- .globl _start
- .type   _start,%function
- .p2align       2
-_start:
-  bl thumbfunc
-  bx lr
-
- .thumb
- .section .text.2, "ax", %progbits
- .globl thumbfunc
- .type thumbfunc,%function
-thumbfunc:
- bx lr

diff  --git a/lld/test/ELF/arm-blx.s b/lld/test/ELF/arm-blx.s
index 73e1d87baa5b..84ecf736906d 100644
--- a/lld/test/ELF/arm-blx.s
+++ b/lld/test/ELF/arm-blx.s
@@ -1,6 +1,6 @@
 // REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
 // RUN: echo "SECTIONS { \
 // RUN:          . = 0xb4; \
 // RUN:          .callee1 : { *(.callee_low) } \

diff  --git a/lld/test/ELF/arm-bx-v4t.s b/lld/test/ELF/arm-bx-v4t.s
new file mode 100644
index 000000000000..8fd6e97053e7
--- /dev/null
+++ b/lld/test/ELF/arm-bx-v4t.s
@@ -0,0 +1,98 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv4t-none-linux-gnueabi %t/a.s -o %t/a.o
+// RUN: ld.lld %t/a.o --script %t/far.lds -o %t/a-far
+// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-far | FileCheck %s --check-prefixes=FAR
+// RUN: ld.lld %t/a.o --script %t/near.lds -o %t/a-near
+// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-near | FileCheck %s --check-prefixes=NEAR
+
+/// On Arm v4t there is no blx instruction so all interworking must go via
+/// a thunk.
+
+#--- a.s
+ .text
+ .syntax unified
+ .cpu    arm7tdmi
+
+ .section .low, "ax", %progbits
+ .arm
+ .globl _start
+ .type   _start,%function
+ .p2align       2
+_start:
+  bl target
+  bx lr
+
+// FAR-LABEL: <_start>:
+// FAR-NEXT:   1000000:       bl      0x1000008 <__ARMv4ABSLongBXThunk_target> @ imm = #0
+// FAR-NEXT:                  bx      lr
+// FAR-EMPTY:
+// FAR-NEXT:  <__ARMv4ABSLongBXThunk_target>:
+// FAR-NEXT:   1000008:       ldr     r12, [pc]               @ 0x1000010 <__ARMv4ABSLongBXThunk_target+0x8>
+// FAR-NEXT:                  bx      r12
+// FAR-EMPTY:
+// FAR-NEXT:  <$d>:
+// FAR-NEXT:   1000010: 01 00 00 06   .word   0x06000001
+
+// NEAR-LABEL: <_start>:
+// NEAR-NEXT:   1000000:       bl      0x1000008 <__ARMv4ABSLongBXThunk_target> @ imm = #0
+// NEAR-NEXT:                  bx      lr
+// NEAR-EMPTY:
+// NEAR-NEXT:  <__ARMv4ABSLongBXThunk_target>:
+// NEAR-NEXT:   1000008:       ldr     r12, [pc]               @ 0x1000010 <__ARMv4ABSLongBXThunk_target+0x8>
+// NEAR-NEXT:                  bx      r12
+// NEAR-EMPTY:
+// NEAR-NEXT:  <$d>:
+// NEAR-NEXT:  1000010: 15 00 00 01   .word   0x01000015
+
+
+.section .high, "ax", %progbits
+.thumb
+ .globl target
+ .type target,%function
+target:
+  bl _start
+  bx lr
+
+// FAR-LABEL: <target>:
+// FAR-NEXT:   6000000:       bl      0x6000008 <__Thumbv4ABSLongBXThunk__start> @ imm = #4
+// FAR-NEXT:                  bx      lr
+// FAR-NEXT:                  bmi     0x5ffffb2 <__ARMv4ABSLongBXThunk_target+0x4ffffaa> @ imm = #-88
+// FAR-EMPTY:
+// FAR-NEXT:  <__Thumbv4ABSLongBXThunk__start>:
+// FAR-NEXT:   6000008:       bx      pc
+// FAR-NEXT:                  b       0x6000008 <__Thumbv4ABSLongBXThunk__start> @ imm = #-6
+// FAR-EMPTY:
+// FAR-NEXT:  <$a>:
+// FAR-NEXT:   600000c:       ldr     pc, [pc, #-4]           @ 0x6000010 <__Thumbv4ABSLongBXThunk__start+0x8>
+// FAR-EMPTY:
+// FAR-NEXT: <$d>:
+// FAR-NEXT:  6000010: 00 00 00 01   .word   0x01000000
+
+// NEAR-LABEL: <target>:
+// NEAR-NEXT:   1000014:       bl      0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #4
+// NEAR-NEXT:   1000018:       bx      lr
+// NEAR-NEXT:   100001a:       bmi     0xffffc6                @ imm = #-88
+// NEAR-EMPTY:
+// NEAR-NEXT:  <__Thumbv4ABSLongBXThunk__start>:
+// NEAR-NEXT:   100001c:       bx      pc
+// NEAR-NEXT:   100001e:       b       0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #-6
+// NEAR-EMPTY:
+// NEAR-NEXT:  <$a>:
+// NEAR-NEXT:   1000020:       ldr     pc, [pc, #-4]           @ 0x1000024 <__Thumbv4ABSLongBXThunk__start+0x8>
+// NEAR-EMPTY:
+// NEAR-NEXT:  <$d>:
+// NEAR-NEXT:   1000024: 00 00 00 01   .word   0x01000000
+
+#--- far.lds
+SECTIONS {
+  . = SIZEOF_HEADERS;
+  .low 0x01000000 : { *(.low) }
+  .high 0x06000000 : { *(.high) }
+}
+
+#--- near.lds
+SECTIONS {
+  . = SIZEOF_HEADERS;
+  .all 0x01000000 : { *(.low) *(.high) }
+}

diff  --git a/lld/test/ELF/arm-thumb-interwork-thunk-v5.s b/lld/test/ELF/arm-thumb-interwork-thunk-v5.s
index 1e77b636f86d..846bebb62425 100644
--- a/lld/test/ELF/arm-thumb-interwork-thunk-v5.s
+++ b/lld/test/ELF/arm-thumb-interwork-thunk-v5.s
@@ -27,7 +27,7 @@ _start:
         bx lr
 
 // CHECK: <_start>:
-// CHECK-NEXT: 21000: ea000003        b       0x21014 <__ARMv5ABSLongThunk_thumb_func>
+// CHECK-NEXT: 21000: ea000003        b       0x21014 <__ARMv5LongLdrPcThunk_thumb_func>
 // CHECK-NEXT: 21004: fa000001        blx     0x21010 <thumb_func>
 // CHECK-NEXT: 21008: fa000000        blx     0x21010 <thumb_func>
 // CHECK-NEXT: 2100c: e12fff1e        bx      lr
@@ -35,13 +35,13 @@ _start:
 // CHECK: <thumb_func>:
 // CHECK-NEXT: 21010: 4770    bx      lr
 
-// CHECK: <__ARMv5ABSLongThunk_thumb_func>:
+// CHECK: <__ARMv5LongLdrPcThunk_thumb_func>:
 // CHECK-NEXT: 21014: e51ff004        ldr     pc, [pc, #-4]
 // CHECK: <$d>:
 // CHECK-NEXT: 21018: 11 10 02 00     .word   0x00021011
 
 // CHECK-PI: <_start>:
-// CHECK-PI-NEXT: 11000: ea000003        b       0x11014 <__ARMV5PILongThunk_thumb_func>
+// CHECK-PI-NEXT: 11000: ea000003        b       0x11014 <__ARMv4PILongThunk_thumb_func>
 // CHECK-PI-NEXT: 11004: fa000001        blx     0x11010 <thumb_func>
 // CHECK-PI-NEXT: 11008: fa000000        blx     0x11010 <thumb_func>
 // CHECK-PI-NEXT: 1100c: e12fff1e        bx      lr
@@ -49,7 +49,7 @@ _start:
 // CHECK-PI: <thumb_func>:
 // CHECK-PI-NEXT: 11010: 4770    bx      lr
 
-// CHECK-PI: <__ARMV5PILongThunk_thumb_func>:
+// CHECK-PI: <__ARMv4PILongThunk_thumb_func>:
 // CHECK-PI-NEXT: 11014: e59fc004        ldr     r12, [pc, #4]
 // CHECK-PI-NEXT: 11018: e08fc00c        add     r12, pc, r12
 // CHECK-PI-NEXT: 1101c: e12fff1c        bx      r12

diff  --git a/lld/test/ELF/arm-thunk-multipass-plt.s b/lld/test/ELF/arm-thunk-multipass-plt.s
index 3932d77e3a04..32f7fb0a3aaa 100644
--- a/lld/test/ELF/arm-thunk-multipass-plt.s
+++ b/lld/test/ELF/arm-thunk-multipass-plt.s
@@ -42,7 +42,7 @@ needsplt:
         .section .text.07, "ax", %progbits
         .space (1024 * 1024)
 /// 0xd00040 = preemptible at plt
-// CHECK:      0070000c <__ARMV5PILongThunk_preemptible>:
+// CHECK:      0070000c <__ARMv4PILongThunk_preemptible>:
 // CHECK-NEXT:   70000c: b       0xd00040
 
         .section .text.08, "ax", %progbits
@@ -52,7 +52,7 @@ needsplt:
         .balign 2
         bl preemptible
         bl preemptible2
-// CHECK-CALL: 80000c: blx     0x70000c <__ARMV5PILongThunk_preemptible>
+// CHECK-CALL: 80000c: blx     0x70000c <__ARMv4PILongThunk_preemptible>
         .balign 2
         .globl preemptible
         .type preemptible, %function


        


More information about the llvm-commits mailing list