[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

llvm-svn: 316752
This commit is contained in:
Peter Smith 2017-10-27 09:04:11 +00:00
parent f0c70f8d34
commit 75030b6d56
22 changed files with 1111 additions and 80 deletions

View File

@ -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 *ISD, uint64_t Off) const {
}
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, RelType Type, const InputFile *File,
// 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;
}

View File

@ -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, uint64_t GotPltEntryAddr,
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

View File

@ -1072,12 +1072,18 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) {
// 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<OutputSection *> OutputSections) {
});
}
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();
// 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;
}
// 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");
// 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::addThunkSection(OutputSection *OS,
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::forEachInputSectionDescription(
// 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<OutputSection *> OutputSections) {
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<OutputSection *> OutputSections) {
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;
}

View File

@ -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);

View File

@ -124,7 +124,7 @@ int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
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;
}

View File

@ -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;

View File

@ -318,11 +318,13 @@ static Thunk *addThunkArm(RelType Reloc, SymbolBody &S) {
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);

View File

@ -1352,17 +1352,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// 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");
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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