[lld] r316752 - [ELF] Introduce range extension thunks for ARM

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 27 02:04:11 PDT 2017


Author: psmith
Date: Fri Oct 27 02:04:11 2017
New Revision: 316752

URL: http://llvm.org/viewvc/llvm-project?rev=316752&view=rev
Log:
[ELF] Introduce range extension thunks for ARM

This change adds initial support for range extension thunks. All thunks must
be created within the first pass so some corner cases are not supported. A
follow up patch will add support for multiple passes.

With this change the existing tests arm-branch-error.s and
arm-thumb-branch-error.s now no longer fail with an out of range branch.
These have been renamed and tests added for the range extension thunk.

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


Added:
    lld/trunk/test/ELF/arm-branch-rangethunk.s
    lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s
    lld/trunk/test/ELF/arm-thumb-mix-range-thunk-os.s
    lld/trunk/test/ELF/arm-thumb-plt-range-thunk-os.s
    lld/trunk/test/ELF/arm-thumb-range-thunk-os.s
    lld/trunk/test/ELF/arm-thunk-largesection.s
    lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s
    lld/trunk/test/ELF/arm-thunk-linkerscript-large.s
    lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s
    lld/trunk/test/ELF/arm-thunk-linkerscript-sort.s
    lld/trunk/test/ELF/arm-thunk-linkerscript.s
    lld/trunk/test/ELF/arm-thunk-toolargesection.s
Removed:
    lld/trunk/test/ELF/arm-branch-error.s
    lld/trunk/test/ELF/arm-thumb-branch-error.s
Modified:
    lld/trunk/ELF/Arch/ARM.cpp
    lld/trunk/ELF/Arch/Mips.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Relocations.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h
    lld/trunk/ELF/Thunks.cpp
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Arch/ARM.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/ARM.cpp?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/ARM.cpp (original)
+++ lld/trunk/ELF/Arch/ARM.cpp Fri Oct 27 02:04:11 2017
@@ -40,7 +40,7 @@ public:
   void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override;
   void addPltHeaderSymbols(InputSectionBase *ISD) const override;
   bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
-                  const SymbolBody &S) const override;
+                  uint64_t BranchAddr, const SymbolBody &S) const override;
   bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
   void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
 };
@@ -228,7 +228,7 @@ void ARM::addPltSymbols(InputSectionBase
 }
 
 bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
-                     const SymbolBody &S) const {
+                     uint64_t BranchAddr, const SymbolBody &S) const {
   // If S is an undefined weak symbol in an executable we don't need a Thunk.
   // In a DSO calls to undefined symbols, including weak ones get PLT entries
   // which may need a thunk.
@@ -245,14 +245,22 @@ bool ARM::needsThunk(RelExpr Expr, RelTy
     // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
     if (Expr == R_PC && ((S.getVA() & 1) == 1))
       return true;
-    break;
+    LLVM_FALLTHROUGH;
+  case R_ARM_CALL: {
+    uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA();
+    return !inBranchRange(Type, BranchAddr, Dst);
+  }
   case R_ARM_THM_JUMP19:
   case R_ARM_THM_JUMP24:
     // Source is Thumb, all PLT entries are ARM so interworking is required.
     // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
     if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0))
       return true;
-    break;
+    LLVM_FALLTHROUGH;
+  case R_ARM_THM_CALL: {
+    uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA();
+    return !inBranchRange(Type, BranchAddr, Dst);
+  }
   }
   return false;
 }

Modified: lld/trunk/ELF/Arch/Mips.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/Mips.cpp?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/Mips.cpp (original)
+++ lld/trunk/ELF/Arch/Mips.cpp Fri Oct 27 02:04:11 2017
@@ -39,7 +39,7 @@ public:
   void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
                 int32_t Index, unsigned RelOff) const override;
   bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
-                  const SymbolBody &S) const override;
+                  uint64_t BranchAddr, const SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   bool usesOnlyLowPageBits(RelType Type) const override;
 };
@@ -331,7 +331,7 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf,
 
 template <class ELFT>
 bool MIPS<ELFT>::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
-                            const SymbolBody &S) const {
+                            uint64_t BranchAddr, const SymbolBody &S) const {
   // Any MIPS PIC code function is invoked with its address in register $t9.
   // So if we have a branch instruction from non-PIC code to the PIC one
   // we cannot make the jump directly and need to create a small stubs

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Fri Oct 27 02:04:11 2017
@@ -1072,12 +1072,18 @@ void ThunkCreator::mergeThunks(ArrayRef<
           // std::merge requires a strict weak ordering.
           if (A->OutSecOff < B->OutSecOff)
             return true;
-          if (A->OutSecOff == B->OutSecOff)
+          if (A->OutSecOff == B->OutSecOff) {
+            auto *TA = dyn_cast<ThunkSection>(A);
+            auto *TB = dyn_cast<ThunkSection>(B);
             // Check if Thunk is immediately before any specific Target
             // InputSection for example Mips LA25 Thunks.
-            if (auto *TA = dyn_cast<ThunkSection>(A))
-              if (TA && TA->getTargetInputSection() == B)
-                return true;
+            if (TA && TA->getTargetInputSection() == B)
+              return true;
+            if (TA && !TB && !TA->getTargetInputSection())
+              // Place Thunk Sections without specific targets before
+              // non-Thunk Sections.
+              return true;
+          }
           return false;
         };
         std::merge(ISD->Sections.begin(), ISD->Sections.end(),
@@ -1088,17 +1094,32 @@ void ThunkCreator::mergeThunks(ArrayRef<
       });
 }
 
-ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *OS,
-                                           InputSectionDescription *ISD) {
-  // FIXME: When range extension thunks are supported we will need to check
-  // that the ThunkSection is in range of the caller.
-  if (!ISD->ThunkSections.empty())
-    return ISD->ThunkSections.front();
-
-  // FIXME: When range extension thunks are supported we must handle the case
-  // where no pre-created ThunkSections are in range by creating a new one in
-  // range; for now, it is unreachable.
-  llvm_unreachable("Must have created at least one ThunkSection per ISR");
+// Find or create a ThunkSection within the InputSectionDescription (ISD) that
+// is in range of Src. An ISR maps to a range of InputSections described by a
+// linker script section pattern such as { .text .text.* }.
+ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *OS, InputSection *IS,
+                                           InputSectionDescription *ISD,
+                                           uint32_t Type, uint64_t Src) {
+  for (ThunkSection *TS : ISD->ThunkSections) {
+    uint64_t TSBase = OS->Addr + TS->OutSecOff;
+    uint64_t TSLimit = TSBase + TS->getSize();
+    if (Target->inBranchRange(Type, Src, (Src > TSLimit) ? TSBase : TSLimit))
+      return TS;
+  }
+
+  // No suitable ThunkSection exists. This can happen when there is a branch
+  // with lower range than the ThunkSection spacing or when there are too
+  // many Thunks. Create a new ThunkSection as close to the InputSection as
+  // possible. Error if InputSection is so large we cannot place ThunkSection
+  // anywhere in Range.
+  uint64_t ThunkSecOff = IS->OutSecOff;
+  if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff)) {
+    ThunkSecOff = IS->OutSecOff + IS->getSize();
+    if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff))
+      fatal("InputSection too large for range extension thunk " +
+            IS->getObjMsg(Src - (OS->Addr + IS->OutSecOff)));
+  }
+  return addThunkSection(OS, ISD, ThunkSecOff);
 }
 
 // Add a Thunk that needs to be placed in a ThunkSection that immediately
@@ -1165,13 +1186,14 @@ ThunkSection *ThunkCreator::addThunkSect
   return TS;
 }
 
-std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body,
-                                                RelType Type) {
+std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body, RelType Type,
+                                                uint64_t Src) {
   auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()});
   if (!Res.second) {
     // Check existing Thunks for Body to see if they can be reused
     for (Thunk *ET : Res.first->second)
-      if (ET->isCompatibleWith(Type))
+      if (ET->isCompatibleWith(Type) &&
+          Target->inBranchRange(Type, Src, ET->ThunkSym->getVA()))
         return std::make_pair(ET, false);
   }
   // No existing compatible Thunk in range, create a new one
@@ -1202,8 +1224,7 @@ void ThunkCreator::forEachInputSectionDe
 // finalized. If any Thunks are added to an InputSectionDescription the
 // offsets within the OutputSection of the InputSections will change.
 //
-// FIXME: All Thunks are assumed to be in range of the relocation. Range
-// extension Thunks are not yet supported.
+// FIXME: Initial support for RangeThunks; only one pass supported.
 bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
   bool AddressesChanged = false;
   if (Pass == 0 && Target->ThunkSectionSpacing)
@@ -1219,12 +1240,13 @@ bool ThunkCreator::createThunks(ArrayRef
         for (InputSection *IS : ISD->Sections)
           for (Relocation &Rel : IS->Relocations) {
             SymbolBody &Body = *Rel.Sym;
+            uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset;
             if (Thunks.find(&Body) != Thunks.end() ||
-                !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
+                !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src, Body))
               continue;
             Thunk *T;
             bool IsNew;
-            std::tie(T, IsNew) = getThunk(Body, Rel.Type);
+            std::tie(T, IsNew) = getThunk(Body, Rel.Type, Src);
             if (IsNew) {
               AddressesChanged = true;
               // Find or create a ThunkSection for the new Thunk
@@ -1232,7 +1254,7 @@ bool ThunkCreator::createThunks(ArrayRef
               if (auto *TIS = T->getTargetInputSection())
                 TS = getISThunkSec(TIS);
               else
-                TS = getISDThunkSec(OS, ISD);
+                TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src);
               TS->addThunk(T);
               Thunks[T->ThunkSym] = T;
             }

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Fri Oct 27 02:04:11 2017
@@ -139,7 +139,11 @@ public:
 
 private:
   void mergeThunks(ArrayRef<OutputSection *> OutputSections);
-  ThunkSection *getISDThunkSec(OutputSection *OS, InputSectionDescription *ISD);
+
+  ThunkSection *getISDThunkSec(OutputSection *OS, InputSection *IS,
+                               InputSectionDescription *ISD, uint32_t Type,
+                               uint64_t Src);
+
   ThunkSection *getISThunkSec(InputSection *IS);
 
   void createInitialThunkSections(ArrayRef<OutputSection *> OutputSections);
@@ -148,7 +152,8 @@ private:
       ArrayRef<OutputSection *> OutputSections,
       std::function<void(OutputSection *, InputSectionDescription *)> Fn);
 
-  std::pair<Thunk *, bool> getThunk(SymbolBody &Body, RelType Type);
+  std::pair<Thunk *, bool> getThunk(SymbolBody &Body, RelType Type,
+                                    uint64_t Src);
 
   ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *,
                                 uint64_t Off);

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Fri Oct 27 02:04:11 2017
@@ -124,7 +124,7 @@ int64_t TargetInfo::getImplicitAddend(co
 bool TargetInfo::usesOnlyLowPageBits(RelType Type) const { return false; }
 
 bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
-                            const SymbolBody &S) const {
+                            uint64_t BranchAddr, const SymbolBody &S) const {
   return false;
 }
 

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Fri Oct 27 02:04:11 2017
@@ -51,12 +51,12 @@ public:
 
   // Decide whether a Thunk is needed for the relocation from File
   // targeting S.
-  virtual bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
+  virtual bool needsThunk(RelExpr Expr, RelType RelocType,
+                          const InputFile *File, uint64_t BranchAddr,
                           const SymbolBody &S) const;
-
-  // Return true if we can reach Dst from Src with Relocation Type
-  virtual bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const;
-
+  // Return true if we can reach Dst from Src with Relocation RelocType
+  virtual bool inBranchRange(RelType Type, uint64_t Src,
+                             uint64_t Dst) const;
   virtual RelExpr getRelExpr(RelType Type, const SymbolBody &S,
                              const uint8_t *Loc) const = 0;
 

Modified: lld/trunk/ELF/Thunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Thunks.cpp?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Thunks.cpp (original)
+++ lld/trunk/ELF/Thunks.cpp Fri Oct 27 02:04:11 2017
@@ -318,11 +318,13 @@ static Thunk *addThunkArm(RelType Reloc,
   case R_ARM_PC24:
   case R_ARM_PLT32:
   case R_ARM_JUMP24:
+  case R_ARM_CALL:
     if (Config->Pic)
       return make<ARMV7PILongThunk>(S);
     return make<ARMV7ABSLongThunk>(S);
   case R_ARM_THM_JUMP19:
   case R_ARM_THM_JUMP24:
+  case R_ARM_THM_CALL:
     if (Config->Pic)
       return make<ThumbV7PILongThunk>(S);
     return make<ThumbV7ABSLongThunk>(S);

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=316752&r1=316751&r2=316752&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Oct 27 02:04:11 2017
@@ -1352,17 +1352,12 @@ template <class ELFT> void Writer<ELFT>:
   // It is linker's responsibility to create thunks containing long
   // jump instructions if jump targets are too far. Create thunks.
   if (Target->NeedsThunks) {
-    // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented,
-    // these
-    // do not require address information. To support range extension Thunks
-    // we need to assign addresses so that we can tell if jump instructions
-    // are out of range. This will need to turn into a loop that converges
-    // when no more Thunks are added
     ThunkCreator TC;
     Script->assignAddresses();
     if (TC.createThunks(OutputSections)) {
       applySynthetic({InX::MipsGot},
                      [](SyntheticSection *SS) { SS->updateAllocSize(); });
+      Script->assignAddresses();
       if (TC.createThunks(OutputSections))
         fatal("All non-range thunks should be created in first call");
     }

Removed: lld/trunk/test/ELF/arm-branch-error.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-branch-error.s?rev=316751&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-branch-error.s (original)
+++ lld/trunk/test/ELF/arm-branch-error.s (removed)
@@ -1,19 +0,0 @@
-// 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-abs.s -o %tfar
-// RUN: not ld.lld  %t %tfar -o %t2 2>&1 | FileCheck %s
-// REQUIRES: arm
- .syntax unified
- .section .text, "ax",%progbits
- .globl _start
- .balign 0x10000
- .type _start,%function
-_start:
- // address of too_far symbols are just out of range of ARM branch with
- // 26-bit immediate field and an addend of -8
- bl  too_far1
- b   too_far2
- beq too_far3
-
-// CHECK: R_ARM_CALL out of range
-// CHECK-NEXT: R_ARM_JUMP24 out of range
-// CHECK-NEXT: R_ARM_JUMP24 out of range

Added: lld/trunk/test/ELF/arm-branch-rangethunk.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-branch-rangethunk.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-branch-rangethunk.s (added)
+++ lld/trunk/test/ELF/arm-branch-rangethunk.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,34 @@
+// 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-abs.s -o %tfar
+// RUN: ld.lld  %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl  too_far1
+ b   too_far2
+ beq too_far3
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:    20000:       01 00 00 eb     bl      #4 <__ARMv7ABSLongThunk_too_far1>
+// CHECK-NEXT:    20004:       03 00 00 ea     b       #12 <__ARMv7ABSLongThunk_too_far2>
+// CHECK-NEXT:    20008:       05 00 00 0a     beq     #20 <__ARMv7ABSLongThunk_too_far3>
+// CHECK: __ARMv7ABSLongThunk_too_far1:
+// CHECK-NEXT:    2000c:       08 c0 00 e3     movw    r12, #8
+// CHECK-NEXT:    20010:       02 c2 40 e3     movt    r12, #514
+// CHECK-NEXT:    20014:       1c ff 2f e1     bx      r12
+// CHECK: __ARMv7ABSLongThunk_too_far2:
+// CHECK-NEXT:    20018:       0c c0 00 e3     movw    r12, #12
+// CHECK-NEXT:    2001c:       02 c2 40 e3     movt    r12, #514
+// CHECK-NEXT:    20020:       1c ff 2f e1     bx      r12
+// CHECK: __ARMv7ABSLongThunk_too_far3:
+// CHECK-NEXT:    20024:       10 c0 00 e3     movw    r12, #16
+// CHECK-NEXT:    20028:       02 c2 40 e3     movt    r12, #514
+// CHECK-NEXT:    2002c:       1c ff 2f e1     bx      r12

Removed: lld/trunk/test/ELF/arm-thumb-branch-error.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-branch-error.s?rev=316751&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thumb-branch-error.s (original)
+++ lld/trunk/test/ELF/arm-thumb-branch-error.s (removed)
@@ -1,19 +0,0 @@
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
-// RUN: not ld.lld  %t %tfar -o %t2 2>&1 | FileCheck %s
-// REQUIRES: arm
- .syntax unified
- .section .text, "ax",%progbits
- .globl _start
- .balign 0x10000
- .type _start,%function
-_start:
- // address of too_far symbols are just out of range of ARM branch with
- // 26-bit immediate field and an addend of -8
- bl  too_far1
- b   too_far2
- beq.w too_far3
-
-// CHECK: R_ARM_THM_CALL out of range
-// CHECK-NEXT: R_ARM_THM_JUMP24 out of range
-// CHECK-NEXT: R_ARM_THM_JUMP19 out of range

Added: lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s (added)
+++ lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,36 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
+// RUN: ld.lld  %t %tfar -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2
+// REQUIRES: arm
+ .syntax unified
+ .thumb
+ .section .text, "ax",%progbits
+ .globl _start
+ .balign 0x10000
+ .type _start,%function
+_start:
+ // address of too_far symbols are just out of range of ARM branch with
+ // 26-bit immediate field and an addend of -8
+ bl  too_far1
+ b   too_far2
+ beq.w too_far3
+
+// CHECK: Disassembly of section .text:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:    20000:       00 f0 04 f8     bl      #8
+// CHECK-NEXT:    20004:       00 f0 07 b8     b.w     #14 <__Thumbv7ABSLongThunk_too_far2>
+// CHECK-NEXT:    20008:       00 f0 0a 80     beq.w   #20 <__Thumbv7ABSLongThunk_too_far3>
+// CHECK: __Thumbv7ABSLongThunk_too_far1:
+// CHECK-NEXT:    2000c:       40 f2 05 0c     movw    r12, #5
+// CHECK-NEXT:    20010:       c0 f2 02 1c     movt    r12, #258
+// CHECK-NEXT:    20014:       60 47   bx      r12
+// CHECK: __Thumbv7ABSLongThunk_too_far2:
+// CHECK-NEXT:    20016:       40 f2 09 0c     movw    r12, #9
+// CHECK-NEXT:    2001a:       c0 f2 02 1c     movt    r12, #258
+// CHECK-NEXT:    2001e:       60 47   bx      r12
+// CHECK: __Thumbv7ABSLongThunk_too_far3:
+// CHECK-NEXT:    20020:       40 f2 0d 0c     movw    r12, #13
+// CHECK-NEXT:    20024:       c0 f2 12 0c     movt    r12, #18
+// CHECK-NEXT:    20028:       60 47   bx      r12
+// CHECK-NEXT:    2002a:       00 00   movs    r0, r0

Added: lld/trunk/test/ELF/arm-thumb-mix-range-thunk-os.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-mix-range-thunk-os.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thumb-mix-range-thunk-os.s (added)
+++ lld/trunk/test/ELF/arm-thumb-mix-range-thunk-os.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,195 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// The output file is large, most of it zeroes. We dissassemble only the
+// parts we need to speed up the test and avoid a large output file
+// RUN: llvm-objdump -d %t2 -start-address=1048576 -stop-address=1048604 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t2 -start-address=2097152 -stop-address=2097162 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t2 -start-address=16777220 -stop-address=16777232 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d %t2 -start-address=16777232 -stop-address=16777242 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s
+// RUN: llvm-objdump -d %t2 -start-address=32505860 -stop-address=32505870 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK5 %s
+// RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651590 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s
+// RUN: llvm-objdump -d %t2 -start-address=36700160 -stop-address=36700168 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s
+// RUN: llvm-objdump -d %t2 -start-address=48234500 -stop-address=48234512 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s
+// RUN: llvm-objdump -d %t2 -start-address=63963140 -stop-address=63963160 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s
+// RUN: llvm-objdump -d %t2 -start-address=68157440 -stop-address=68157452 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK10 %s
+// RUN: llvm-objdump -d %t2 -start-address=69206016 -stop-address=69206024 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK11 %s
+
+// Test the Range extension Thunks for ARM and Thumb when all the code is in a
+// single OutputSection. The ARM branches and branch and link instructions
+// have a range of 32Mb, the Thumb unconditional branch and
+// branch and link instructions have . We create a series of Functions a
+// megabyte apart. We expect range extension thunks to be created when a
+// branch is out of range. Thunks will be reused whenever they are in range
+ .syntax unified
+
+// Define a function aligned on a megabyte boundary
+ .macro ARMFUNCTION suff
+ .section .text.\suff\(), "ax", %progbits
+ .arm
+ .balign 0x100000
+ .globl afunc\suff\()
+ .type  afunc\suff\(), %function
+afunc\suff\():
+ bx lr
+ .endm
+
+// Define a function aligned on a megabyte boundary
+ .macro THUMBFUNCTION suff
+ .section .text.\suff\(), "ax", %progbits
+ .thumb
+ .balign 0x100000
+ .globl tfunc\suff\()
+ .type  tfunc\suff\(), %function
+tfunc\suff\():
+ bx lr
+ .endm
+
+ .section .text, "ax", %progbits
+ .thumb
+ .globl _start
+_start:
+
+ ARMFUNCTION 00
+// Expect ARM bl to be in range (can use blx to change state)
+ bl tfunc31
+// ARM b and beq are in range but need Thunk to change state to Thumb
+ b  tfunc31
+ beq tfunc31
+// afunc32 is out of range of ARM branch and branch and link
+ bl afunc32
+ b  afunc32
+ bne afunc32
+// CHECK1:  afunc00:
+// CHECK1-NEXT:   100000:       1e ff 2f e1     bx      lr
+// CHECK1-NEXT:   100004:       fd ff 7b fa     blx     #32505844
+// CHECK1-NEXT:   100008:       fd ff 3b ea     b       #15728628
+// CHECK1-NEXT:   10000c:       fc ff 3b 0a     beq     #15728624
+// CHECK1-NEXT:   100010:       fa ff 7f eb     bl      #33554408
+// CHECK1-NEXT:   100014:       f9 ff 7f ea     b       #33554404
+// CHECK1-NEXT:   100018:       f8 ff 7f 1a     bne     #33554400
+ THUMBFUNCTION 01
+// Expect Thumb bl to be in range (can use blx to change state)
+ bl afunc14
+// In range but need thunk to change state to Thumb
+ b.w afunc14
+// CHECK2: tfunc01:
+// CHECK2-NEXT:   200000:       70 47   bx      lr
+// CHECK2-NEXT:   200002:       ff f0 fe c7     blx     #13631484
+// CHECK2-NEXT:   200006:       00 f2 03 90     b.w     #14680070 <__Thumbv7ABSLongThunk_afunc14>
+
+ ARMFUNCTION 02
+ THUMBFUNCTION 03
+ ARMFUNCTION 04
+ THUMBFUNCTION 05
+ ARMFUNCTION 06
+ THUMBFUNCTION 07
+ ARMFUNCTION 08
+ THUMBFUNCTION 09
+ ARMFUNCTION 10
+ THUMBFUNCTION 11
+ ARMFUNCTION 12
+ THUMBFUNCTION 13
+ ARMFUNCTION 14
+// CHECK3:   __ARMv7ABSLongThunk_tfunc31:
+// CHECK3-NEXT:  1000004:       01 c0 00 e3     movw    r12, #1
+// CHECK3-NEXT:  1000008:       00 c2 40 e3     movt    r12, #512
+// CHECK3-NEXT:  100000c:       1c ff 2f e1     bx      r12
+// CHECK4: __Thumbv7ABSLongThunk_afunc14:
+// CHECK4-NEXT:  1000010:       40 f2 00 0c     movw    r12, #0
+// CHECK4-NEXT:  1000014:       c0 f2 f0 0c     movt    r12, #240
+// CHECK4-NEXT:  1000018:       60 47   bx      r12
+ THUMBFUNCTION 15
+ ARMFUNCTION 16
+ THUMBFUNCTION 17
+ ARMFUNCTION 18
+ THUMBFUNCTION 19
+ ARMFUNCTION 20
+ THUMBFUNCTION 21
+ ARMFUNCTION 22
+ THUMBFUNCTION 23
+ ARMFUNCTION 24
+ THUMBFUNCTION 25
+ ARMFUNCTION 26
+ THUMBFUNCTION 27
+ ARMFUNCTION 28
+ THUMBFUNCTION 29
+ ARMFUNCTION 30
+// Expect precreated Thunk Section here
+// CHECK5: __Thumbv7ABSLongThunk_afunc00:
+// CHECK5-NEXT:  1f00004:       40 f2 00 0c     movw    r12, #0
+// CHECK5-NEXT:  1f00008:       c0 f2 10 0c     movt    r12, #16
+// CHECK5-NEXT:  1f0000c:       60 47   bx      r12
+ THUMBFUNCTION 31
+ ARMFUNCTION 32
+ THUMBFUNCTION 33
+// Out of range, can only reach closest Thunk Section
+ bl afunc00
+// CHECK6:  tfunc33:
+// CHECK6-NEXT:  2200000:       70 47   bx      lr
+// CHECK6-NEXT:  2200002:       ff f4 ff ff     bl      #-3145730
+ ARMFUNCTION 34
+// Out of range, can reach earlier Thunk Section
+// CHECK7:  afunc34:
+// CHECK7-NEXT:  2300000:       1e ff 2f e1     bx      lr
+// CHECK7-NEXT:  2300004:       fe ff ef fa     blx     #-4194312 <__Thumbv7ABSLongThunk_afunc00
+ bl afunc00
+ THUMBFUNCTION 35
+ ARMFUNCTION 36
+ THUMBFUNCTION 37
+ ARMFUNCTION 38
+ THUMBFUNCTION 39
+ ARMFUNCTION 40
+ THUMBFUNCTION 41
+ ARMFUNCTION 42
+ THUMBFUNCTION 43
+ ARMFUNCTION 44
+ THUMBFUNCTION 45
+// Expect precreated Thunk Section here
+// CHECK8: __ARMv7ABSLongThunk_tfunc35:
+// CHECK8-NEXT:  2e00004:       01 c0 00 e3     movw    r12, #1
+// CHECK8-NEXT:  2e00008:       40 c2 40 e3     movt    r12, #576
+// CHECK8-NEXT:  2e0000c:       1c ff 2f e1     bx      r12
+ ARMFUNCTION 46
+ THUMBFUNCTION 47
+ ARMFUNCTION 48
+ THUMBFUNCTION 49
+ ARMFUNCTION 50
+ THUMBFUNCTION 51
+ ARMFUNCTION 52
+ THUMBFUNCTION 53
+ ARMFUNCTION 54
+ THUMBFUNCTION 55
+ ARMFUNCTION 56
+ THUMBFUNCTION 57
+ ARMFUNCTION 58
+ THUMBFUNCTION 59
+ ARMFUNCTION 60
+// Expect precreated Thunk Section here
+// CHECK9: __Thumbv7ABSLongThunk_afunc34:
+// CHECK9-NEXT:  3d00004:       40 f2 00 0c     movw    r12, #0
+// CHECK9-NEXT:  3d00008:       c0 f2 30 2c     movt    r12, #560
+// CHECK9-NEXT:  3d0000c:       60 47   bx      r12
+// CHECK9: __Thumbv7ABSLongThunk_tfunc35:
+// CHECK9-NEXT:  3d0000e:       40 f2 01 0c     movw    r12, #1
+// CHECK9-NEXT:  3d00012:       c0 f2 40 2c     movt    r12, #576
+// CHECK9-NEXT:  3d00016:       60 47   bx      r12
+ THUMBFUNCTION 61
+ ARMFUNCTION 62
+ THUMBFUNCTION 63
+ ARMFUNCTION 64
+// afunc34 is in range, as is tfunc35 but a branch needs a state change Thunk
+ bl afunc34
+ b  tfunc35
+// CHECK10: afunc64:
+// CHECK10-NEXT:  4100000:       1e ff 2f e1     bx      lr
+// CHECK10-NEXT:  4100004:      fd ff 87 eb     bl      #-31457292 <afunc34>
+// CHECK10-NEXT:  4100008:      fd ff b3 ea     b       #-19922956 <__ARMv7ABSLongThunk_tfunc35>
+ THUMBFUNCTION 65
+// afunc34 and tfunc35 are both out of range
+ bl afunc34
+ bl tfunc35
+// CHECK11: tfunc65:
+// CHECK11:  4200000:   70 47   bx      lr
+// CHECK11-NEXT:  4200002:      ff f6 ff f7     bl      #-5242882
+// CHECK11-NEXT:  4200006:      00 f7 02 f0     bl      #-5242876

Added: lld/trunk/test/ELF/arm-thumb-plt-range-thunk-os.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-plt-range-thunk-os.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thumb-plt-range-thunk-os.s (added)
+++ lld/trunk/test/ELF/arm-thumb-plt-range-thunk-os.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,88 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t --shared -o %t.so
+// The output file is large, most of it zeroes. We dissassemble only the
+// parts we need to speed up the test and avoid a large output file
+// RUN: llvm-objdump -d %t.so -start-address=8388608 -stop-address=8388624 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t.so -start-address=16777216 -stop-address=16777256 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t.so -start-address=25165824 -stop-address=25165828 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d %t.so -start-address=25165828 -stop-address=25165908 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s
+ .syntax unified
+ .thumb
+
+// Make sure that we generate a range extension thunk to a PLT entry
+ .section ".text.1", "ax", %progbits
+ .global sym1
+ .global elsewhere
+ .type elsewhere, %function
+ .global preemptible
+ .type preemptible, %function
+ .global far_preemptible
+ .type far_preemptible, %function
+sym1:
+ bl elsewhere
+ bl preemptible
+ bx lr
+preemptible:
+ bl far_preemptible
+ bx lr
+// CHECK1: Disassembly of section .text:
+// CHECK1-NEXT: sym1:
+// CHECK1-NEXT:   800000:       00 f0 00 d8     bl      #8388608
+// CHECK1-NEXT:   800004:       00 f0 04 d8     bl      #8388616
+// CHECK1-NEXT:   800008:       70 47   bx      lr
+// CHECK1: preemptible:
+// CHECK1-NEXT:   80000a:       00 f0 07 d8     bl      #8388622
+// CHECK1-NEXT:   80000e:       70 47   bx      lr
+
+ .section .text.2, "ax", %progbits
+ .balign 0x0800000
+ bx lr
+// CHECK2: __ThumbV7PILongThunk_elsewhere:
+// CHECK2-NEXT:  1000004:       40 f2 14 0c     movw    r12, #20
+// CHECK2-NEXT:  1000008:       c0 f2 80 0c     movt    r12, #128
+// CHECK2-NEXT:  100000c:       fc 44   add     r12, pc
+// CHECK2-NEXT:  100000e:       60 47   bx      r12
+// CHECK2: __ThumbV7PILongThunk_preemptible:
+// CHECK2-NEXT:  1000010:       40 f2 18 0c     movw    r12, #24
+// CHECK2-NEXT:  1000014:       c0 f2 80 0c     movt    r12, #128
+// CHECK2-NEXT:  1000018:       fc 44   add     r12, pc
+// CHECK2-NEXT:  100001a:       60 47   bx      r12
+// CHECK2: __ThumbV7PILongThunk_far_preemptible:
+// CHECK2-NEXT:  100001c:       40 f2 1c 0c     movw    r12, #28
+// CHECK2-NEXT:  1000020:       c0 f2 80 0c     movt    r12, #128
+// CHECK2-NEXT:  1000024:       fc 44   add     r12, pc
+// CHECK2-NEXT:  1000026:       60 47   bx      r12
+ .section .text.3, "ax", %progbits
+.balign 0x0800000
+far_preemptible:
+ bl elsewhere
+// CHECK3: far_preemptible:
+// CHECK3:  1800000:       00 f0 10 e8     blx     #32
+
+// CHECK4: Disassembly of section .plt:
+// CHECK4-NEXT: $a:
+// CHECK4-NEXT:  1800010:       04 e0 2d e5     str     lr, [sp, #-4]!
+// CHECK4-NEXT:  1800014:       04 e0 9f e5     ldr     lr, [pc, #4]
+// CHECK4-NEXT:  1800018:       0e e0 8f e0     add     lr, pc, lr
+// CHECK4-NEXT:  180001c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// CHECK4: $d:
+// CHECK4-NEXT:  1800020:       e0 0f 00 00     .word   0x00000fe0
+// CHECK4: $a:
+// CHECK4-NEXT:  1800024:       04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK4-NEXT:  1800028:       0f c0 8c e0     add     r12, r12, pc
+// CHECK4-NEXT:  180002c:       00 f0 9c e5     ldr     pc, [r12]
+// CHECK4: $d:
+// CHECK4-NEXT:  1800030:       dc 0f 00 00     .word   0x00000fdc
+// CHECK4: $a:
+// CHECK4-NEXT:  1800034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK4-NEXT:  1800038:       0f c0 8c e0     add     r12, r12, pc
+// CHECK4-NEXT:  180003c:       00 f0 9c e5     ldr     pc, [r12]
+// CHECK4: $d:
+// CHECK4-NEXT:  1800040:       d0 0f 00 00     .word   0x00000fd0
+// CHECK4: $a:
+// CHECK4-NEXT:  1800044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// CHECK4-NEXT:  1800048:       0f c0 8c e0     add     r12, r12, pc
+// CHECK4-NEXT:  180004c:       00 f0 9c e5     ldr     pc, [r12]
+// CHECK4: $d:
+// CHECK4-NEXT:  1800050:       c4 0f 00 00     .word   0x00000fc4

Added: lld/trunk/test/ELF/arm-thumb-range-thunk-os.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thumb-range-thunk-os.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thumb-range-thunk-os.s (added)
+++ lld/trunk/test/ELF/arm-thumb-range-thunk-os.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,159 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// The output file is large, most of it zeroes. We dissassemble only the
+// parts we need to speed up the test and avoid a large output file
+// RUN: llvm-objdump -d %t2 -start-address=1048576 -stop-address=1048588 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t2 -start-address=2097152 -stop-address=2097154 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t2 -start-address=3145728 -stop-address=3145730 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d %t2 -start-address=4194304 -stop-address=4194310 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s
+// RUN: llvm-objdump -d %t2 -start-address=16777216 -stop-address=16777270 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK5 %s
+// RUN: llvm-objdump -d %t2 -start-address=17825792 -stop-address=17825808 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s
+// RUN: llvm-objdump -d %t2 -start-address=31457280 -stop-address=31457286 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s
+// RUN: llvm-objdump -d %t2 -start-address=32505860 -stop-address=32505880 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s
+// RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651594 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s
+// RUN: llvm-objdump -d %t2 -start-address=36700160 -stop-address=36700170 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK10 %s
+
+// Test the Range extension Thunks for Thumb when all the code is in a single
+// OutputSection. The Thumb unconditional branch b.w and branch and link bl
+// instructions have a range of 16Mb. We create a series of Functions a
+// megabyte apart. We expect range extension thunks to be created when a
+// branch is out of range. Thunks will be reused whenever they are in range
+ .syntax unified
+
+// Define a function aligned on a megabyte boundary
+ .macro FUNCTION suff
+ .section .text.\suff\(), "ax", %progbits
+ .thumb
+ .balign 0x100000
+ .globl tfunc\suff\()
+ .type  tfunc\suff\(), %function
+tfunc\suff\():
+ bx lr
+ .endm
+
+ .section .text, "ax", %progbits
+ .thumb
+ .globl _start
+_start:
+// tfunc00 and tfunc15 are within 16Mb no Range Thunks expected
+ bl tfunc00
+ bl tfunc15
+// tfunc16 is > 16Mb away, expect a Range Thunk to be generated, to go into
+// the first of the pre-created ThunkSections.
+ bl tfunc16
+// CHECK1: Disassembly of section .text:
+// CHECK1-NEXT: _start:
+// CHECK1-NEXT:   100000:       ff f0 fe ff     bl      #1048572
+// CHECK1-NEXT:   100004:       ff f3 fc d7     bl      #16777208
+// CHECK1-NEXT:   100008:       ff f2 fc d7     bl      #15728632
+
+ FUNCTION 00
+// CHECK2:  tfunc00:
+// CHECK2-NEXT:   200000:       70 47   bx      lr
+        FUNCTION 01
+// CHECK3: tfunc01:
+// CHECK3-NEXT:   300000:       70 47   bx      lr
+ FUNCTION 02
+// tfunc28 is > 16Mb away, expect a Range Thunk to be generated, to go into
+// the first of the pre-created ThunkSections.
+        b.w tfunc28
+// CHECK4: tfunc02:
+// CHECK4-NEXT:   400000:       70 47   bx      lr
+// CHECK4-NEXT:   400002:       00 f0 04 90     b.w     #12582920 <__Thumbv7ABSLongThunk_tfunc28>
+ FUNCTION 03
+ FUNCTION 04
+ FUNCTION 05
+ FUNCTION 06
+ FUNCTION 07
+ FUNCTION 08
+ FUNCTION 09
+ FUNCTION 10
+ FUNCTION 11
+ FUNCTION 12
+ FUNCTION 13
+ FUNCTION 14
+// Expect precreated ThunkSection here
+// CHECK5: __Thumbv7ABSLongThunk_tfunc16:
+// CHECK5-NEXT:  1000004:       40 f2 01 0c     movw    r12, #1
+// CHECK5-NEXT:  1000008:       c0 f2 20 1c     movt    r12, #288
+// CHECK5-NEXT:  100000c:       60 47   bx      r12
+// CHECK5: __Thumbv7ABSLongThunk_tfunc28:
+// CHECK5-NEXT:  100000e:       40 f2 01 0c     movw    r12, #1
+// CHECK5-NEXT:  1000012:       c0 f2 e0 1c     movt    r12, #480
+// CHECK5-NEXT:  1000016:       60 47   bx      r12
+// CHECK5: __Thumbv7ABSLongThunk_tfunc32:
+// CHECK5-NEXT:  1000018:       40 f2 01 0c     movw    r12, #1
+// CHECK5-NEXT:  100001c:       c0 f2 20 2c     movt    r12, #544
+// CHECK5-NEXT:  1000020:       60 47   bx      r12
+// CHECK5: __Thumbv7ABSLongThunk_tfunc33:
+// CHECK5-NEXT:  1000022:       40 f2 01 0c     movw    r12, #1
+// CHECK5-NEXT:  1000026:       c0 f2 30 2c     movt    r12, #560
+// CHECK5-NEXT:  100002a:       60 47   bx      r12
+// CHECK5: __Thumbv7ABSLongThunk_tfunc02:
+// CHECK5-NEXT:  100002c:       40 f2 01 0c     movw    r12, #1
+// CHECK5-NEXT:  1000030:       c0 f2 40 0c     movt    r12, #64
+// CHECK5-NEXT:  1000034:       60 47   bx      r12
+ FUNCTION 15
+// tfunc00 and tfunc01 are < 16Mb away, expect no range extension thunks
+ bl tfunc00
+ bl tfunc01
+// tfunc32 and tfunc33 are > 16Mb away, expect range extension thunks in the
+// precreated thunk section
+ bl tfunc32
+ bl tfunc33
+// CHECK6:  tfunc15:
+// CHECK6-NEXT:  1100000:       70 47   bx      lr
+// CHECK6-NEXT:  1100002:       ff f4 fd d7     bl      #-15728646
+// CHECK6-NEXT:  1100006:       ff f5 fb d7     bl      #-14680074
+// CHECK6-NEXT:  110000a:       00 f7 05 f8     bl      #-1048566
+// CHECK6-NEXT:  110000e:       00 f7 08 f8     bl      #-1048560
+ FUNCTION 16
+ FUNCTION 17
+ FUNCTION 18
+ FUNCTION 19
+ FUNCTION 20
+ FUNCTION 21
+ FUNCTION 22
+ FUNCTION 23
+ FUNCTION 24
+ FUNCTION 25
+ FUNCTION 26
+ FUNCTION 27
+ FUNCTION 28
+// tfunc02 is > 16Mb away, expect range extension thunks in precreated thunk
+// section
+// CHECK7:  tfunc28:
+// CHECK7-NEXT:  1e00000:       70 47   bx      lr
+// CHECK7-NEXT:  1e00002:       00 f6 13 90     b.w     #-14680026 <__Thumbv7ABSLongThunk_tfunc02>
+
+ b.w tfunc02
+ FUNCTION 29
+// Expect another precreated thunk section here
+// CHECK8: __Thumbv7ABSLongThunk_tfunc15:
+// CHECK8-NEXT:  1f00004:       40 f2 01 0c     movw    r12, #1
+// CHECK8-NEXT:  1f00008:       c0 f2 10 1c     movt    r12, #272
+// CHECK8-NEXT:  1f0000c:       60 47   bx      r12
+// CHECK8: __Thumbv7ABSLongThunk_tfunc16:
+// CHECK8-NEXT:  1f0000e:       40 f2 01 0c     movw    r12, #1
+// CHECK8-NEXT:  1f00012:       c0 f2 20 1c     movt    r12, #288
+// CHECK8-NEXT:  1f00016:       60 47   bx      r12
+ FUNCTION 30
+ FUNCTION 31
+ FUNCTION 32
+ // tfunc15 and tfunc16 are > 16 Mb away expect Thunks in the nearest
+ // precreated thunk section.
+ bl tfunc15
+ bl tfunc16
+// CHECK9: tfunc32:
+// CHECK9:  2200000:    70 47   bx      lr
+// CHECK9-NEXT:  2200002:       ff f4 ff ff     bl      #-3145730
+// CHECK9-NEXT:  2200006:       00 f5 02 f8     bl      #-3145724
+
+ FUNCTION 33
+ bl tfunc15
+ bl tfunc16
+// CHECK10: tfunc33:
+// CHECK10:  2300000:   70 47   bx      lr
+// CHECK10-NEXT:  2300002:      ff f7 ff f7     bl      #-4194306
+// CHECK10-NEXT:  2300006:      00 f4 02 f8     bl      #-4194300

Added: lld/trunk/test/ELF/arm-thunk-largesection.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-largesection.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-largesection.s (added)
+++ lld/trunk/test/ELF/arm-thunk-largesection.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,42 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=69632 -stop-address=69636 %t2 | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=73732 -stop-address=73742 %t2 | FileCheck -check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=16850944 -stop-address=16850948 %t2 | FileCheck -check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=33628160 -stop-address=33628164 %t2 | FileCheck -check-prefix=CHECK4 %s
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=50405364 -stop-address=50405376 %t2 | FileCheck -check-prefix=CHECK5 %s
+// REQUIRES: arm
+ .syntax unified
+ .balign 0x1000
+ .thumb
+ .text
+ .globl _start
+ .type _start, %function
+_start:
+ bx lr
+ .space 0x1000
+// CHECK1: Disassembly of section .text:
+// CHECK1-NEXT: _start:
+// CHECK1-NEXT:    11000:       70 47   bx      lr
+// CHECK1-NEXT:    11002:       00 00   movs    r0, r0
+
+// CHECK2: __Thumbv7ABSLongThunk__start:
+// CHECK2-NEXT:    12004:       41 f2 01 0c     movw    r12, #4097
+// CHECK2-NEXT:    12008:       c0 f2 01 0c     movt    r12, #1
+// CHECK2-NEXT:    1200c:       60 47   bx      r12
+
+// Gigantic section where we need a ThunkSection either side of it
+ .section .text.large1, "ax", %progbits
+ .balign 4
+ .space (16 * 1024 * 1024) - 16
+ bl _start
+ .space (16 * 1024 * 1024) - 4
+ bl _start
+ .space (16 * 1024 * 1024) - 16
+// CHECK3: 1012000:     00 f4 00 d0     bl      #-16777216
+// CHECK4: 2012000:     ff f3 f8 d7     bl      #16777200
+
+// CHECK5: __Thumbv7ABSLongThunk__start:
+// CHECK5-NEXT:  3011ff4:       41 f2 01 0c     movw    r12, #4097
+// CHECK5-NEXT:  3011ff8:       c0 f2 01 0c     movt    r12, #1
+// CHECK5-NEXT:  3011ffc:       60 47   bx      r12

Added: lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s (added)
+++ lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,76 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       . = SIZEOF_HEADERS; \
+// RUN:       .text_low : { *(.text_low) *(.text_low2) . = . + 0x2000000 ; *(.text_high) *(.text_high2) } \
+// RUN:       } " > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// RUN: llvm-objdump -d %t2 -start-address=148 -stop-address=188 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t2 -start-address=33554620 -stop-address=33554654 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+// Test that range extension thunks can handle location expressions within
+// a Section Description
+ .syntax unified
+ .section .text_low, "ax", %progbits
+ .thumb
+ .globl _start
+_start: bx lr
+ .globl low_target
+ .type low_target, %function
+low_target:
+ bl high_target
+ bl high_target2
+
+ .section .text_low2, "ax", %progbits
+ .thumb
+ .globl low_target2
+ .type low_target2, %function
+low_target2:
+ bl high_target
+ bl high_target2
+// CHECK1: Disassembly of section .text_low:
+// CHECK1-NEXT: _start:
+// CHECK1-NEXT:       94:       70 47   bx      lr
+// CHECK1: low_target:
+// CHECK1-NEXT:       96:       00 f0 03 f8     bl      #6
+// CHECK1-NEXT:       9a:       00 f0 06 f8     bl      #12
+// CHECK1: __Thumbv7ABSLongThunk_high_target:
+// CHECK1-NEXT:       a0:       40 f2 bd 0c     movw    r12, #189
+// CHECK1-NEXT:       a4:       c0 f2 00 2c     movt    r12, #512
+// CHECK1-NEXT:       a8:       60 47   bx      r12
+// CHECK1: __Thumbv7ABSLongThunk_high_target2:
+// CHECK1-NEXT:       aa:       40 f2 d9 0c     movw    r12, #217
+// CHECK1-NEXT:       ae:       c0 f2 00 2c     movt    r12, #512
+// CHECK1-NEXT:       b2:       60 47   bx      r12
+// CHECK1: low_target2:
+// CHECK1-NEXT:       b4:       ff f7 f4 ff     bl      #-24
+// CHECK1-NEXT:       b8:       ff f7 f7 ff     bl      #-18
+
+ .section .text_high, "ax", %progbits
+ .thumb
+ .globl high_target
+ .type high_target, %function
+high_target:
+ bl low_target
+ bl low_target2
+
+ .section .text_high2, "ax", %progbits
+ .thumb
+ .globl high_target2
+ .type high_target2, %function
+high_target2:
+ bl low_target
+ bl low_target2
+
+// CHECK2: high_target:
+// CHECK2-NEXT:  20000bc:       00 f0 02 f8     bl      #4
+// CHECK2-NEXT:  20000c0:       00 f0 05 f8     bl      #10
+// CHECK2: __Thumbv7ABSLongThunk_low_target:
+// CHECK2-NEXT:  20000c4:       40 f2 97 0c     movw    r12, #151
+// CHECK2-NEXT:  20000c8:       c0 f2 00 0c     movt    r12, #0
+// CHECK2-NEXT:  20000cc:       60 47   bx      r12
+// CHECK2: __Thumbv7ABSLongThunk_low_target2:
+// CHECK2-NEXT:  20000ce:       40 f2 b5 0c     movw    r12, #181
+// CHECK2-NEXT:  20000d2:       c0 f2 00 0c     movt    r12, #0
+// CHECK2-NEXT:  20000d6:       60 47   bx      r12
+// CHECK2: high_target2:
+// CHECK2-NEXT:  20000d8:       ff f7 f4 ff     bl      #-24
+// CHECK2-NEXT:  20000dc:       ff f7 f7 ff     bl      #-18

Added: lld/trunk/test/ELF/arm-thunk-linkerscript-large.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-linkerscript-large.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-linkerscript-large.s (added)
+++ lld/trunk/test/ELF/arm-thunk-linkerscript-large.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,176 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       .text 0x100000 : { *(.text) } \
+// RUN:       .textl : { *(.text_l0*) *(.text_l1*) *(.text_l2*) *(.text_l3*) } \
+// RUN:       .texth : { *(.text_h0*) *(.text_h1*) *(.text_h2*) *(.text_h3*) } \
+// RUN:       }" > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// The output file is large, most of it zeroes. We dissassemble only the
+// parts we need to speed up the test and avoid a large output file
+// RUN: llvm-objdump -d %t2 -start-address=1048576 -stop-address=1048594 -triple=thumbv7a-linux-gnueabihf | FileCheck --check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t2 -start-address=2097152 -stop-address=2097160 -triple=thumbv7a-linux-gnueabihf | FileCheck --check-prefix=CHECK2 %s
+// RUN: llvm-objdump -d %t2 -start-address=11534340 -stop-address=11534350 -triple=thumbv7a-linux-gnueabihf | FileCheck --check-prefix=CHECK3 %s
+// RUN: llvm-objdump -d %t2 -start-address=34603008 -stop-address=34603034 -triple=thumbv7a-linux-gnueabihf | FileCheck --check-prefix=CHECK4 %s
+// RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651598 -triple=thumbv7a-linux-gnueabihf | FileCheck --check-prefix=CHECK5 %s
+// RUN: llvm-objdump -d %t2 -start-address=68157440 -stop-address=68157472 -triple=thumbv7a-linux-gnueabihf | FileCheck --check-prefix=CHECK6 %s
+
+// Test the range extensions in a linker script where there are several
+// OutputSections requiring range extension Thunks. We should be able to reuse
+// Thunks between OutputSections but our placement of new Thunks is done on a
+// per OutputSection basis
+ .syntax unified
+
+// Define a function that we can match with .text_l* aligned on a megabyte      // boundary
+ .macro FUNCTIONL suff
+ .section .text_l\suff\(), "ax", %progbits
+ .thumb
+ .balign 0x100000
+ .globl tfuncl\suff\()
+ .type  tfuncl\suff\(), %function
+tfuncl\suff\():
+ bx lr
+ .endm
+
+// Define a function that we can match with .text_h* aligned on a megabyte
+// boundary
+ .macro FUNCTIONH suff
+ .section .text_h\suff\(), "ax", %progbits
+ .thumb
+ .balign 0x100000
+ .globl tfunch\suff\()
+ .type  tfunch\suff\(), %function
+tfunch\suff\():
+ bx lr
+ .endm
+
+ .section .text, "ax", %progbits
+ .thumb
+ .globl _start
+_start:
+ bl tfuncl00
+ // Expect a range extension thunk in .text OutputSection
+ bl tfunch31
+// CHECK1: Disassembly of section .text:
+// CHECK1-NEXT: _start:
+// CHECK1-NEXT:   100000:       ff f0 fe ff     bl      #1048572
+// CHECK1-NEXT:   100004:       00 f0 00 f8     bl      #0
+// CHECK1: __Thumbv7ABSLongThunk_tfunch31:
+// CHECK1-NEXT:   100008:       40 f2 01 0c     movw    r12, #1
+// CHECK1-NEXT:   10000c:       c0 f2 10 4c     movt    r12, #1040
+// CHECK1-NEXT:   100010:       60 47   bx      r12
+ FUNCTIONL 00
+ // Create a range extension thunk in .textl
+ bl tfuncl24
+ // We can reuse existing thunk in .text
+ bl tfunch31
+// CHECK2: Disassembly of section .textl:
+// CHECK2-NEXT: tfuncl00:
+// CHECK2-NEXT:   200000:	70 47 	bx	lr
+// CHECK2-NEXT:   200002:	ff f0 ff df 	bl	#9437182
+// CHECK2-NEXT:   200006:	ff f6 ff ff 	bl	#-1048578
+ FUNCTIONL 01
+ FUNCTIONL 02
+ FUNCTIONL 03
+ FUNCTIONL 04
+ FUNCTIONL 05
+ FUNCTIONL 06
+ FUNCTIONL 07
+ FUNCTIONL 08
+ FUNCTIONL 09
+// CHECK3: __Thumbv7ABSLongThunk_tfuncl24:
+// CHECK3-NEXT:   b00004:	40 f2 01 0c 	movw	r12, #1
+// CHECK3-NEXT:   b00008:	c0 f2 a0 1c 	movt	r12, #416
+// CHECK3-NEXT:   b0000c:	60 47 	bx	r12
+ FUNCTIONL 10
+ FUNCTIONL 11
+ FUNCTIONL 12
+ FUNCTIONL 13
+ FUNCTIONL 14
+ FUNCTIONL 15
+ FUNCTIONL 16
+ FUNCTIONL 17
+ FUNCTIONL 18
+ FUNCTIONL 19
+ FUNCTIONL 20
+ FUNCTIONL 21
+ FUNCTIONL 22
+ FUNCTIONL 23
+ FUNCTIONL 24
+ FUNCTIONL 25
+ FUNCTIONL 26
+ FUNCTIONL 27
+ FUNCTIONL 28
+ FUNCTIONL 29
+ FUNCTIONL 30
+ FUNCTIONL 31
+ // Create range extension thunks in .textl
+ bl tfuncl00
+ bl tfuncl24
+ // Shouldn't need a thunk
+ bl tfunch00
+// CHECK4:  2100002:    00 f0 05 f8     bl      #10
+// CHECK4-NEXT:  2100006:       ff f4 fb f7     bl      #-7340042
+// CHECK4-NEXT:  210000a:       ff f0 f9 ff     bl      #1048562
+// CHECK4: __Thumbv7ABSLongThunk_tfuncl00:
+// CHECK4-NEXT:  2100010:       40 f2 01 0c     movw    r12, #1
+// CHECK4-NEXT:  2100014:       c0 f2 20 0c     movt    r12, #32
+// CHECK4-NEXT:  2100018:       60 47   bx      r12
+ FUNCTIONH 00
+ // Can reuse existing thunks in .textl
+ bl tfuncl00
+ bl tfuncl24
+ // Shouldn't need a thunk
+        bl tfuncl31
+// CHECK5:  Disassembly of section .texth:
+// CHECK5-NEXT: tfunch00:
+// CHECK5-NEXT:  2200000:       70 47   bx      lr
+// CHECK5-NEXT:  2200002:       00 f7 05 f8     bl      #-1048566
+// CHECK5-NEXT:  2200006:       ff f7 fb df     bl      #-8388618
+// CHECK5-NEXT:  220000a:       ff f6 f9 ff     bl      #-1048590
+ FUNCTIONH 01
+ FUNCTIONH 02
+ FUNCTIONH 03
+ FUNCTIONH 04
+ FUNCTIONH 05
+ FUNCTIONH 06
+ FUNCTIONH 07
+ FUNCTIONH 08
+ FUNCTIONH 09
+ FUNCTIONH 10
+ FUNCTIONH 11
+ FUNCTIONH 12
+ FUNCTIONH 13
+ FUNCTIONH 14
+ FUNCTIONH 15
+ FUNCTIONH 16
+ FUNCTIONH 17
+ FUNCTIONH 18
+ FUNCTIONH 19
+ FUNCTIONH 20
+ FUNCTIONH 21
+ FUNCTIONH 22
+ FUNCTIONH 23
+ FUNCTIONH 24
+ FUNCTIONH 25
+ FUNCTIONH 26
+ FUNCTIONH 27
+ FUNCTIONH 28
+ FUNCTIONH 29
+ FUNCTIONH 30
+ FUNCTIONH 31
+// expect Thunks in .texth
+ bl tfuncl00
+ bl tfunch00
+// CHECK6: tfunch31:
+// CHECK6-NEXT:  4100000:       70 47   bx      lr
+// CHECK6-NEXT:  4100002:       00 f0 03 f8     bl      #6
+// CHECK6-NEXT:  4100006:       00 f0 06 f8     bl      #12
+// CHECK6: __Thumbv7ABSLongThunk_tfuncl00:
+// CHECK6-NEXT:  410000c:       40 f2 01 0c     movw    r12, #1
+// CHECK6-NEXT:  4100010:       c0 f2 20 0c     movt    r12, #32
+// CHECK6-NEXT:  4100014:       60 47   bx      r12
+// CHECK6: __Thumbv7ABSLongThunk_tfunch00:
+// CHECK6-NEXT:  4100016:       40 f2 01 0c     movw    r12, #1
+// CHECK6-NEXT:  410001a:       c0 f2 20 2c     movt    r12, #544
+// CHECK6-NEXT:  410001e:       60 47   bx      r12

Added: lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s (added)
+++ lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,63 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       .text_low 0x100000 : { *(.text_low) } \
+// RUN:       .text_high 0x2000000 : { *(.text_high) } \
+// RUN:       .data : { *(.data) } \
+// RUN:       }" > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
+ .syntax unified
+ .section .text_low, "ax", %progbits
+ .thumb
+ .globl _start
+_start: bx lr
+ .globl low_target
+ .type low_target, %function
+low_target:
+ bl high_target
+ bl orphan_target
+// CHECK: Disassembly of section .text_low:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:   100000:        70 47   bx      lr
+// CHECK: low_target:
+// CHECK-NEXT:   100002:        00 f0 03 f8     bl      #6
+// CHECK-NEXT:   100006:        00 f0 06 f8     bl      #12
+// CHECK: __Thumbv7ABSLongThunk_high_target:
+// CHECK-NEXT:   10000c:        40 f2 01 0c     movw    r12, #1
+// CHECK-NEXT:   100010:        c0 f2 00 2c     movt    r12, #512
+// CHECK-NEXT:   100014:        60 47   bx      r12
+// CHECK: __Thumbv7ABSLongThunk_orphan_target:
+// CHECK-NEXT:   100016:        40 f2 15 0c     movw    r12, #21
+// CHECK-NEXT:   10001a:        c0 f2 00 2c     movt    r12, #512
+// CHECK-NEXT:   10001e:        60 47   bx      r12
+  .section .text_high, "ax", %progbits
+ .thumb
+ .globl high_target
+ .type high_target, %function
+high_target:
+ bl low_target
+ bl orphan_target
+// CHECK: Disassembly of section .text_high:
+// CHECK-NEXT: high_target:
+// CHECK-NEXT:  2000000:        00 f0 02 f8     bl      #4
+// CHECK-NEXT:  2000004:        00 f0 06 f8     bl      #12
+// CHECK: __Thumbv7ABSLongThunk_low_target:
+// CHECK-NEXT:  2000008:        40 f2 03 0c     movw    r12, #3
+// CHECK-NEXT:  200000c:        c0 f2 10 0c     movt    r12, #16
+// CHECK-NEXT:  2000010:        60 47   bx      r12
+
+ .section orphan, "ax", %progbits
+ .thumb
+ .globl orphan_target
+ .type orphan_target, %function
+orphan_target:
+ bl low_target
+ bl high_target
+// CHECK: Disassembly of section orphan:
+// CHECK-NEXT: orphan_target:
+// CHECK-NEXT:  2000014:        ff f7 f8 ff     bl      #-16
+// CHECK-NEXT:  2000018:        ff f7 f2 ff     bl      #-28
+
+ .data
+ .word 10

Added: lld/trunk/test/ELF/arm-thunk-linkerscript-sort.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-linkerscript-sort.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-linkerscript-sort.s (added)
+++ lld/trunk/test/ELF/arm-thunk-linkerscript-sort.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,71 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       .text 0x100000 : { *(SORT_BY_NAME(.text.*)) } \
+// RUN:       }" > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// RUN: llvm-objdump -d %t2 -start-address=1048576 -stop-address=1048584 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s
+// RUN: llvm-objdump -d %t2 -start-address=16777220 -stop-address=16777230 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
+
+ .syntax unified
+
+// Test that linkerscript sorting does not apply to Thunks, we expect that the
+// sort will reverse the order of sections presented here.
+
+// Define a function aligned on a megabyte boundary
+ .macro FUNCTION suff
+ .section .text.\suff\(), "ax", %progbits
+ .thumb
+ .balign 0x100000
+ .globl tfunc\suff\()
+ .type  tfunc\suff\(), %function
+tfunc\suff\():
+ bx lr
+ .endm
+
+ FUNCTION 31
+ FUNCTION 30
+ FUNCTION 29
+ FUNCTION 28
+ FUNCTION 27
+ FUNCTION 26
+ FUNCTION 25
+ FUNCTION 24
+ FUNCTION 23
+ FUNCTION 22
+ FUNCTION 21
+ FUNCTION 20
+ FUNCTION 19
+ FUNCTION 18
+ FUNCTION 17
+ FUNCTION 16
+ FUNCTION 15
+// CHECK2: __Thumbv7ABSLongThunk_tfunc31:
+// CHECK2-NEXT:  1000004:       40 f2 01 0c     movw    r12, #1
+// CHECK2-NEXT:  1000008:       c0 f2 00 2c     movt    r12, #512
+// CHECK2-NEXT:  100000c:       60 47   bx      r12
+ FUNCTION 14
+ FUNCTION 13
+ FUNCTION 12
+ FUNCTION 11
+ FUNCTION 10
+ FUNCTION 09
+ FUNCTION 08
+ FUNCTION 07
+ FUNCTION 06
+ FUNCTION 05
+ FUNCTION 04
+ FUNCTION 03
+ FUNCTION 02
+ FUNCTION 01
+ .section .text.00, "ax", %progbits
+ .thumb
+ .globl _start
+_start:
+// Expect no range extension needed for tfunc01 and an extension needed for
+// tfunc31
+ bl tfunc01
+ bl tfunc31
+// CHECK1: _start:
+// CHECK1-NEXT:   100000:       ff f0 fe ff     bl      #1048572
+// CHECK1-NEXT:   100004:       ff f2 fe d7     bl      #15728636

Added: lld/trunk/test/ELF/arm-thunk-linkerscript.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-linkerscript.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-linkerscript.s (added)
+++ lld/trunk/test/ELF/arm-thunk-linkerscript.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,78 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN:       . = SIZEOF_HEADERS; \
+// RUN:       .text_low : { *(.text_low) *(.text_low2) } \
+// RUN:       .text_high 0x2000000 : { *(.text_high) *(.text_high2) } \
+// RUN:       } " > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s
+
+// Simple test that we can support range extension thunks with linker scripts
+ .syntax unified
+ .section .text_low, "ax", %progbits
+ .thumb
+ .globl _start
+_start: bx lr
+ .globl low_target
+ .type low_target, %function
+low_target:
+ bl high_target
+ bl high_target2
+
+ .section .text_low2, "ax", %progbits
+ .thumb
+ .globl low_target2
+ .type low_target2, %function
+low_target2:
+ bl high_target
+ bl high_target2
+
+// CHECK: Disassembly of section .text_low:
+// CHECK-NEXT: _start:
+// CHECK-NEXT:       94:        70 47   bx      lr
+// CHECK: low_target:
+// CHECK-NEXT:       96:        00 f0 03 f8     bl      #6
+// CHECK-NEXT:       9a:        00 f0 06 f8     bl      #12
+// CHECK: __Thumbv7ABSLongThunk_high_target:
+// CHECK-NEXT:       a0:        40 f2 01 0c     movw    r12, #1
+// CHECK-NEXT:       a4:        c0 f2 00 2c     movt    r12, #512
+// CHECK-NEXT:       a8:        60 47   bx      r12
+// CHECK: __Thumbv7ABSLongThunk_high_target2:
+// CHECK-NEXT:       aa:        40 f2 1d 0c     movw    r12, #29
+// CHECK-NEXT:       ae:        c0 f2 00 2c     movt    r12, #512
+// CHECK-NEXT:       b2:        60 47   bx      r12
+// CHECK: low_target2:
+// CHECK-NEXT:       b4:        ff f7 f4 ff     bl      #-24
+// CHECK-NEXT:       b8:        ff f7 f7 ff     bl      #-18
+
+ .section .text_high, "ax", %progbits
+ .thumb
+ .globl high_target
+ .type high_target, %function
+high_target:
+ bl low_target
+ bl low_target2
+
+ .section .text_high2, "ax", %progbits
+ .thumb
+ .globl high_target2
+ .type high_target2, %function
+high_target2:
+ bl low_target
+ bl low_target2
+
+// CHECK: Disassembly of section .text_high:
+// CHECK-NEXT: high_target:
+// CHECK-NEXT:  2000000:        00 f0 02 f8     bl      #4
+// CHECK-NEXT:  2000004:        00 f0 05 f8     bl      #10
+// CHECK: __Thumbv7ABSLongThunk_low_target:
+// CHECK-NEXT:  2000008:        40 f2 97 0c     movw    r12, #151
+// CHECK-NEXT:  200000c:        c0 f2 00 0c     movt    r12, #0
+// CHECK-NEXT:  2000010:        60 47   bx      r12
+// CHECK: __Thumbv7ABSLongThunk_low_target2:
+// CHECK-NEXT:  2000012:        40 f2 b5 0c     movw    r12, #181
+// CHECK-NEXT:  2000016:        c0 f2 00 0c     movt    r12, #0
+// CHECK-NEXT:  200001a:        60 47   bx      r12
+// CHECK: high_target2:
+// CHECK-NEXT:  200001c:        ff f7 f4 ff     bl      #-24
+// CHECK-NEXT:  2000020:        ff f7 f7 ff     bl      #-18

Added: lld/trunk/test/ELF/arm-thunk-toolargesection.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/arm-thunk-toolargesection.s?rev=316752&view=auto
==============================================================================
--- lld/trunk/test/ELF/arm-thunk-toolargesection.s (added)
+++ lld/trunk/test/ELF/arm-thunk-toolargesection.s Fri Oct 27 02:04:11 2017
@@ -0,0 +1,19 @@
+// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+// REQUIRES: arm
+ .syntax unified
+ .balign 0x1000
+ .thumb
+ .text
+ .globl _start
+ .type _start, %function
+_start:
+ bx lr
+
+ .section .text.large1, "ax", %progbits
+ .balign 4
+.space (17 * 1024 * 1024)
+ bl _start
+.space (17 * 1024 * 1024)
+
+// CHECK: error: InputSection too large for range extension thunk {{.*}}.text.large1




More information about the llvm-commits mailing list