Index: lld/trunk/ELF/AArch64ErrataFix.cpp =================================================================== --- lld/trunk/ELF/AArch64ErrataFix.cpp +++ lld/trunk/ELF/AArch64ErrataFix.cpp @@ -487,7 +487,7 @@ InputSectionDescription &ISD, std::vector &Patches) { uint64_t ISLimit; uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff; - uint64_t PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); // Set the OutSecOff of patches to the place where we want to insert them. // We use a similar strategy to Thunk placement. Place patches roughly @@ -503,7 +503,7 @@ (*PatchIt)->OutSecOff = PrevISLimit; ++PatchIt; } - PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing(); } PrevISLimit = ISLimit; } Index: lld/trunk/ELF/Arch/AArch64.cpp =================================================================== --- lld/trunk/ELF/Arch/AArch64.cpp +++ lld/trunk/ELF/Arch/AArch64.cpp @@ -41,6 +41,7 @@ int32_t Index, unsigned RelOff) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; + uint32_t getThunkSectionSpacing() const override; bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; bool usesOnlyLowPageBits(RelType Type) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; @@ -70,11 +71,6 @@ // 1 of the tls structures and the tcb size is 16. TcbSize = 16; NeedsThunks = true; - - // See comment in Arch/ARM.cpp for a more detailed explanation of - // ThunkSectionSpacing. For AArch64 the only branches we are permitted to - // Thunk have a range of +/- 128 MiB - ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000; } RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, @@ -208,6 +204,13 @@ return !inBranchRange(Type, BranchAddr, Dst); } +uint32_t AArch64::getThunkSectionSpacing() const { + // See comment in Arch/ARM.cpp for a more detailed explanation of + // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to + // Thunk have a range of +/- 128 MiB + return (128 * 1024 * 1024) - 0x30000; +} + bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) return true; Index: lld/trunk/ELF/Arch/ARM.cpp =================================================================== --- lld/trunk/ELF/Arch/ARM.cpp +++ lld/trunk/ELF/Arch/ARM.cpp @@ -40,6 +40,7 @@ void addPltHeaderSymbols(InputSection &ISD) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; + uint32_t getThunkSectionSpacing() 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; }; @@ -63,37 +64,6 @@ // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; - - // The placing of pre-created ThunkSections is controlled by the - // ThunkSectionSpacing parameter. The aim is to place the - // ThunkSection such that all branches from the InputSections prior to the - // ThunkSection can reach a Thunk placed at the end of the ThunkSection. - // Graphically: - // | up to ThunkSectionSpacing .text input sections | - // | ThunkSection | - // | up to ThunkSectionSpacing .text input sections | - // | ThunkSection | - - // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to - // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W - // ARM B, BL, BLX range +/- 32MiB - // Thumb B.W, BL, BLX range +/- 16MiB - // Thumb B.W range +/- 1MiB - // If a branch cannot reach a pre-created ThunkSection a new one will be - // created so we can handle the rare cases of a Thumb 2 conditional branch. - // We intentionally use a lower size for ThunkSectionSpacing than the maximum - // branch range so the end of the ThunkSection is more likely to be within - // range of the branch instruction that is furthest away. The value we shorten - // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 - // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to - // one of the Thunks going out of range. - - // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and - // J2 bits to be used to extend the branch range. On earlier Architectures - // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If - // support for the earlier encodings is added then when they are used the - // ThunkSectionSpacing will need lowering. - ThunkSectionSpacing = 0x1000000 - 0x30000; } uint32_t ARM::calcEFlags() const { @@ -324,6 +294,40 @@ return false; } +uint32_t ARM::getThunkSectionSpacing() const { + // The placing of pre-created ThunkSections is controlled by the value + // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to + // place the ThunkSection such that all branches from the InputSections + // prior to the ThunkSection can reach a Thunk placed at the end of the + // ThunkSection. Graphically: + // | up to ThunkSectionSpacing .text input sections | + // | ThunkSection | + // | up to ThunkSectionSpacing .text input sections | + // | ThunkSection | + + // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This + // is to match the most common expected case of a Thumb 2 encoded BL, BLX or + // B.W: + // ARM B, BL, BLX range +/- 32MiB + // Thumb B.W, BL, BLX range +/- 16MiB + // Thumb B.W range +/- 1MiB + // If a branch cannot reach a pre-created ThunkSection a new one will be + // created so we can handle the rare cases of a Thumb 2 conditional branch. + // We intentionally use a lower size for ThunkSectionSpacing than the maximum + // branch range so the end of the ThunkSection is more likely to be within + // range of the branch instruction that is furthest away. The value we shorten + // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 + // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to + // one of the Thunks going out of range. + + // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch + // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except + // ARMv6T2) the range is +/- 4MiB. + + return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000 + : 0x400000 - 0x7500; +} + bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { uint64_t Range; uint64_t InstrSize; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -1504,9 +1504,6 @@ if (Config->ARMHasBlx == false) warn("lld uses blx instruction, no object with architecture supporting " "feature detected."); - if (Config->ARMHasMovtMovw == false) - warn("lld may use movt/movw, no object with architecture supporting " - "feature detected."); } // This adds a .comment section containing a version string. We have to add it Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -1268,6 +1268,7 @@ // allow for the creation of a short thunk. void ThunkCreator::createInitialThunkSections( ArrayRef OutputSections) { + uint32_t ThunkSectionSpacing = Target->getThunkSectionSpacing(); forEachInputSectionDescription( OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { if (ISD->Sections.empty()) @@ -1276,18 +1277,18 @@ uint32_t ISDEnd = ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize(); uint32_t LastThunkLowerBound = -1; - if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2) - LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing; + if (ISDEnd - ISDBegin > ThunkSectionSpacing * 2) + LastThunkLowerBound = ISDEnd - ThunkSectionSpacing; uint32_t ISLimit; uint32_t PrevISLimit = ISDBegin; - uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing; + uint32_t ThunkUpperBound = ISDBegin + ThunkSectionSpacing; for (const InputSection *IS : ISD->Sections) { ISLimit = IS->OutSecOff + IS->getSize(); if (ISLimit > ThunkUpperBound) { addThunkSection(OS, ISD, PrevISLimit); - ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + ThunkUpperBound = PrevISLimit + ThunkSectionSpacing; } if (ISLimit > LastThunkLowerBound) break; @@ -1382,7 +1383,7 @@ // relocation out of range error. bool ThunkCreator::createThunks(ArrayRef OutputSections) { bool AddressesChanged = false; - if (Pass == 0 && Target->ThunkSectionSpacing) + if (Pass == 0 && Target->getThunkSectionSpacing()) createInitialThunkSections(OutputSections); else if (Pass == 10) // With Thunk Size much smaller than branch range we expect to Index: lld/trunk/ELF/Target.h =================================================================== --- lld/trunk/ELF/Target.h +++ lld/trunk/ELF/Target.h @@ -61,6 +61,11 @@ const InputFile *File, uint64_t BranchAddr, const Symbol &S) const; + // On systems with range extensions we place collections of Thunks at + // regular spacings that enable the majority of branches reach the Thunks. + // a value of 0 means range extension thunks are not supported. + virtual uint32_t getThunkSectionSpacing() const { return 0; } + // The function with a prologue starting at Loc was compiled with // -fsplit-stack and it calls a function compiled without. Adjust the prologue // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks. @@ -88,10 +93,6 @@ // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. bool GotBaseSymInGotPlt = true; - // On systems with range extensions we place collections of Thunks at - // regular spacings that enable the majority of branches reach the Thunks. - uint32_t ThunkSectionSpacing = 0; - RelType CopyRel; RelType GotRel; RelType PltRel; Index: lld/trunk/ELF/Thunks.cpp =================================================================== --- lld/trunk/ELF/Thunks.cpp +++ lld/trunk/ELF/Thunks.cpp @@ -159,6 +159,31 @@ void addSymbols(ThunkSection &IS) override; }; +// Implementations of Thunks for older Arm architectures that do not support +// the movt/movw instructions. These thunks require at least Architecture v5 +// as used on processors such as the Arm926ej-s. There are no Thumb entry +// points as there is no Thumb branch instruction on these architecture that +// can result in a thunk +class ARMV5ABSLongThunk final : public ARMThunk { +public: + ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {} + + uint32_t sizeLong() override { return 8; } + void writeLong(uint8_t *Buf) override; + void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; +}; + +class ARMV5PILongThunk final : public ARMThunk { +public: + ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {} + + uint32_t sizeLong() override { return 16; } + void writeLong(uint8_t *Buf) override; + void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; +}; + // MIPS LA25 thunk class MipsThunk final : public Thunk { public: @@ -433,6 +458,52 @@ addSymbol("$t", STT_NOTYPE, 0, IS); } +void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) { + const uint8_t Data[] = { + 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 + 0x00, 0x00, 0x00, 0x00, // L1: .word S + }; + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination)); +} + +void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) { + addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()), + STT_FUNC, 0, IS); + addSymbol("$a", STT_NOTYPE, 0, IS); + addSymbol("$d", STT_NOTYPE, 4, IS); +} + +bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + +void ARMV5PILongThunk::writeLong(uint8_t *Buf) { + const uint8_t Data[] = { + 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2 + 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip + 0x1c, 0xff, 0x2f, 0xe1, // bx ip + 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8) + }; + uint64_t S = getARMThunkDestVA(Destination); + uint64_t P = getThunkTargetSym()->getVA() & ~0x1; + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12); +} + +void ARMV5PILongThunk::addSymbols(ThunkSection &IS) { + addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC, + 0, IS); + addSymbol("$a", STT_NOTYPE, 0, IS); + addSymbol("$d", STT_NOTYPE, 12, IS); +} + +bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *Buf) { uint64_t S = Destination.getVA(); @@ -534,10 +605,49 @@ } // Creates a thunk for Thumb-ARM interworking. +// Arm Architectures v5 and v6 do not support Thumb2 technology. This means +// - MOVT and MOVW instructions cannot be used +// - Only Thumb relocation that can generate a Thunk is a BL, this can always +// be transformed into a BLX +static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) { + switch (Reloc) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + case R_ARM_CALL: + case R_ARM_THM_CALL: + if (Config->Pic) + return make(S); + return make(S); + } + fatal("relocation " + toString(Reloc) + " to " + toString(S) + + " not supported for Armv5 or Armv6 targets"); +} + +// Creates a thunk for Thumb-ARM interworking or branch range extension. static Thunk *addThunkArm(RelType Reloc, Symbol &S) { - // ARM relocations need ARM to Thumb interworking Thunks. - // Thumb relocations need Thumb to ARM relocations. - // Use position independent Thunks if we require position independent code. + // Decide which Thunk is needed based on: + // Available instruction set + // - An Arm Thunk can only be used if Arm state is available. + // - A Thumb Thunk can only be used if Thumb state is available. + // - Can only use a Thunk if it uses instructions that the Target supports. + // Relocation is branch or branch and link + // - Branch instructions cannot change state, can only select Thunk that + // starts in the same state as the caller. + // - Branch and link relocations can change state, can select Thunks from + // either Arm or Thumb. + // Position independent Thunks if we require position independent code. + + if (!Config->ARMHasMovtMovw) { + if (!Config->ARMJ1J2BranchEncoding) + return addThunkPreArmv7(Reloc, S); + else + // The Armv6-m architecture (Cortex-M0) does not have Arm instructions or + // support the MOVT MOVW instructions so it cannot use any of the Thunks + // currently implemented. + fatal("thunks not supported for architecture Armv6-m"); + } + switch (Reloc) { case R_ARM_PC24: case R_ARM_PLT32: Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -1166,7 +1166,7 @@ // we effectively double the amount of code that could potentially call into // the hot code without a thunk. size_t InsPt = 0; - if (Target->ThunkSectionSpacing && !OrderedSections.empty()) { + if (Target->getThunkSectionSpacing() && !OrderedSections.empty()) { uint64_t UnorderedPos = 0; for (; InsPt != UnorderedSections.size(); ++InsPt) { UnorderedPos += UnorderedSections[InsPt]->getSize(); Index: lld/trunk/test/ELF/arm-bl-v6.s =================================================================== --- lld/trunk/test/ELF/arm-bl-v6.s +++ lld/trunk/test/ELF/arm-bl-v6.s @@ -1,15 +1,18 @@ // REQUIRES: arm // RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv6-none-linux-gnueabi %s -o %t -// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s +// RUN: ld.lld %t -o %t2 2>&1 +// RUN: llvm-objdump -d -triple=armv6-none-linux-gnueabi -start-address=69632 -stop-address=69640 %t2 | FileCheck -check-prefix=CHECK-ARM1 %s +// RUN: llvm-objdump -d -triple=thumbv6-none-linux-gnueabi %t2 -start-address=69640 -stop-address=69644 | FileCheck -check-prefix=CHECK-THUMB1 %s +// RUN: llvm-objdump -d -triple=armv6-none-linux-gnueabi -start-address=2166796 -stop-address=2166804 %t2 | FileCheck -check-prefix=CHECK-ARM2 %s +// RUN: llvm-objdump -d -triple=thumbv6-none-linux-gnueabi %t2 -start-address=6365184 -stop-address=6365186 | FileCheck -check-prefix=CHECK-THUMB2 %s // On Arm v6 the range of a Thumb BL instruction is only 4 megabytes as the // extended range encoding is not supported. The following example has a Thumb // BL that is out of range on ARM v6 and requires a range extension thunk. // As v6 does not support MOVT or MOVW instructions the Thunk must not -// use these instructions either. At present we don't support v6 so we give a -// warning for unsupported features. +// use these instructions either. + -// CHECK: warning: lld may use movt/movw, no object with architecture supporting feature detected. // ARM v6 supports blx so we shouldn't see the blx not supported warning. // CHECK-NOT: warning: lld uses blx instruction, no object with architecture supporting feature detected. .text @@ -22,6 +25,10 @@ bl thumbfunc bx lr +// CHECK-ARM1: Disassembly of section .text: +// CHECK-ARM1-NEXT: _start: +// CHECK-ARM1-NEXT: 11000: 00 00 00 fa blx #0 +// CHECK-ARM1-NEXT: 11004: 1e ff 2f e1 bx lr .thumb .section .text.2, "ax", %progbits .globl thumbfunc @@ -29,11 +36,17 @@ thumbfunc: bl farthumbfunc -// 6 Megabytes, enough to make farthumbfunc out of range of caller on a v6 -// Arm, but not on a v7 Arm. +// CHECK-THUMB1: thumbfunc: +// CHECK-THUMB1-NEXT: 11008: 00 f2 00 e8 blx #2097152 +// 6 Megabytes, enough to make farthumbfunc out of range of caller +// on a v6 Arm, but not on a v7 Arm. + .section .text.3, "ax", %progbits .space 0x200000 - +// CHECK-ARM2: __ARMv5ABSLongThunk_farthumbfunc: +// CHECK-ARM2-NEXT: 21100c: 04 f0 1f e5 ldr pc, [pc, #-4] +// CHECK-ARM2: $d: +// CHECK-ARM2-NEXT: 211010: 01 20 61 00 .word 0x00612001 .section .text.4, "ax", %progbits .space 0x200000 @@ -47,3 +60,5 @@ .type farthumbfunc,%function farthumbfunc: bx lr +// CHECK-THUMB2: farthumbfunc: +// CHECK-THUMB2-NEXT: 612000: 70 47 bx lr Index: lld/trunk/test/ELF/arm-blx-v4t.s =================================================================== --- lld/trunk/test/ELF/arm-blx-v4t.s +++ lld/trunk/test/ELF/arm-blx-v4t.s @@ -7,7 +7,6 @@ // features. // CHECK: warning: lld uses blx instruction, no object with architecture supporting feature detected. -// CHECK-NEXT: warning: lld may use movt/movw, no object with architecture supporting feature detected. .text .syntax unified Index: lld/trunk/test/ELF/arm-branch-rangethunk.s =================================================================== --- lld/trunk/test/ELF/arm-branch-rangethunk.s +++ lld/trunk/test/ELF/arm-branch-rangethunk.s @@ -1,9 +1,9 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar // RUN: ld.lld %t %tfar -o %t2 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck --check-prefix=SHORT %s -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-long-arm-abs.s -o %tfarlong +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-long-arm-abs.s -o %tfarlong // RUN: ld.lld %t %tfarlong -o %t3 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck --check-prefix=LONG %s .syntax unified Index: lld/trunk/test/ELF/arm-branch-undef-weak-plt-thunk.s =================================================================== --- lld/trunk/test/ELF/arm-branch-undef-weak-plt-thunk.s +++ lld/trunk/test/ELF/arm-branch-undef-weak-plt-thunk.s @@ -1,7 +1,7 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-shared.s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-shared.s -o %t // RUN: ld.lld %t --shared -o %t.so -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2 +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2 // RUN: ld.lld %t2 %t.so -o %t3 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi -start-address=69632 -stop-address=69664 %t3 | FileCheck %s Index: lld/trunk/test/ELF/arm-long-thunk-converge.s =================================================================== --- lld/trunk/test/ELF/arm-long-thunk-converge.s +++ lld/trunk/test/ELF/arm-long-thunk-converge.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -triple armv7-unknown-gnu -filetype=obj -o %t %s +// RUN: llvm-mc -triple armv7-unknown-gnu -arm-add-build-attributes -filetype=obj -o %t %s // RUN: ld.lld %t %S/Inputs/arm-long-thunk-converge.lds -o %t2 // RUN: llvm-objdump -d -start-address=0x00000000 -stop-address=0x00000010 -triple=armv7a-linux-gnueabihf %t2 | FileCheck --check-prefix=CHECK1 %s // RUN: llvm-objdump -d -start-address=0x02000000 -stop-address=0x02000010 -triple=armv7a-linux-gnueabihf %t2 | FileCheck --check-prefix=CHECK2 %s Index: lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s +++ lld/trunk/test/ELF/arm-thumb-branch-rangethunk.s @@ -1,6 +1,6 @@ // REQUIRES: arm -// 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: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -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 .syntax unified Index: lld/trunk/test/ELF/arm-thumb-interwork-shared.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-interwork-shared.s +++ lld/trunk/test/ELF/arm-thumb-interwork-shared.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t --shared -o %t.so // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t.so | FileCheck %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s -check-prefix=PLT Index: lld/trunk/test/ELF/arm-thumb-interwork-thunk-range.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-interwork-thunk-range.s +++ lld/trunk/test/ELF/arm-thumb-interwork-thunk-range.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld %t.o -o /dev/null -image-base=0x80000000 // Test that when the thunk is at a high address we don't get confused with it Index: lld/trunk/test/ELF/arm-thumb-interwork-thunk-v5.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-interwork-thunk-v5.s +++ lld/trunk/test/ELF/arm-thumb-interwork-thunk-v5.s @@ -0,0 +1,66 @@ +// REQUIRES: arm +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv5-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o %t2 +// RUN: llvm-objdump -d %t2 -triple=armv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-ARM %s +// RUN: llvm-objdump -d %t2 -triple=thumbv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-THUMB %s +// RUN: ld.lld %t -o %t3 --shared +// RUN: llvm-objdump -d %t3 -triple=armv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-ARM-PI %s +// RUN: llvm-objdump -d %t3 -triple=thumbv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-THUMB-PI %s + +// Test ARM Thumb Interworking on older Arm architectures using Thunks that do +// not use MOVT/MOVW instructions. +// For pure interworking (not considering range extension) there is only the +// case of an Arm B to a Thumb Symbol to consider as in older Arm architectures +// there is no Thumb B.w that we can intercept with a Thunk and we still assume +// support for the blx instruction for Thumb BL and BLX to an Arm symbol. + .arm + .text + .syntax unified + .cpu arm10tdmi + + .text + .globl _start + .type _start, %function + .balign 0x1000 +_start: + b thumb_func + bl thumb_func + blx thumb_func + bx lr + +// CHECK-ARM: _start: +// CHECK-ARM-NEXT: 11000: 03 00 00 ea b #12 <__ARMv5ABSLongThunk_thumb_func> +// CHECK-ARM-NEXT: 11004: 01 00 00 fa blx #4 +// CHECK-ARM-NEXT: 11008: 00 00 00 fa blx #0 +// CHECK-ARM-NEXT: 1100c: 1e ff 2f e1 bx lr + +// CHECK-THUMB: thumb_func: +// CHECK-THUMB-NEXT: 11010: 70 47 bx lr + +// CHECK-ARM: __ARMv5ABSLongThunk_thumb_func: +// CHECK-ARM-NEXT: 11014: 04 f0 1f e5 ldr pc, [pc, #-4] +// CHECK-ARM: $d: +// CHECK-ARM-NEXT: 11018: 11 10 01 00 .word 0x00011011 + +// CHECK-ARM-PI: _start: +// CHECK-ARM-PI-NEXT: 1000: 03 00 00 ea b #12 <__ARMV5PILongThunk_thumb_func> +// CHECK-ARM-PI-NEXT: 1004: 01 00 00 fa blx #4 +// CHECK-ARM-PI-NEXT: 1008: 00 00 00 fa blx #0 +// CHECK-ARM-PI-NEXT: 100c: 1e ff 2f e1 bx lr + +// CHECK-THUMB-PI: thumb_func: +// CHECK-THUMB-PI-NEXT: 1010: 70 47 bx lr + +// CHECK-ARM-PI: __ARMV5PILongThunk_thumb_func: +// CHECK-ARM-PI-NEXT: 1014: 04 c0 9f e5 ldr r12, [pc, #4] +// CHECK-ARM-PI-NEXT: 1018: 0c c0 8f e0 add r12, pc, r12 +// CHECK-ARM-PI-NEXT: 101c: 1c ff 2f e1 bx r12 +// CHECK-ARM-PI: $d: +// CHECK-ARM-PI-NEXT: 1020: f1 ff ff ff .word 0xfffffff1 + + .section .text.1, "ax", %progbits + .thumb + .hidden thumb_func + .type thumb_func, %function +thumb_func: + bx lr Index: lld/trunk/test/ELF/arm-thumb-interwork-thunk.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-interwork-thunk.s +++ lld/trunk/test/ELF/arm-thumb-interwork-thunk.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ // RUN: .R_ARM_JUMP24_callee_1 : { *(.R_ARM_JUMP24_callee_low) } \ Index: lld/trunk/test/ELF/arm-thumb-nov6thunk.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-nov6thunk.s +++ lld/trunk/test/ELF/arm-thumb-nov6thunk.s @@ -0,0 +1,39 @@ +// REQUIRES: arm +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv6m-none-eabi %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: not ld.lld --script %t.script %t -o %t2 2>&1 | FileCheck %s + +// CHECK: error: thunks not supported for architecture Armv6-m + +// Range extension thunks are not currently supported on Armv6-m due to a +// combination of Armv6-m being aimed at low-end microcontrollers that typically +// have < 512 Kilobytes of memory, and the restrictions of the instruction set +// that make thunks inefficient. The main restriction is that the +// interprocedural scratch register r12 (ip) cannot be accessed from many +// instructions so we must use the stack to avoid corrupting the program. +// +// A v6-m Thunk would look like +// push {r0, r1} ; Make 8-bytes of stack for restoring r0, and destination +// ldr r0, [pc, #4] ; L1 +// str r0, [sp, #4] ; store destination address into sp + 4 +// pop {r0, pc} ; restore r0 and load pc with destination +// L1: .word destination + + .syntax unified + .section .text_low, "ax", %progbits + .thumb + .type _start, %function + .globl _start +_start: + bl far + + .section .text_high, "ax", %progbits + .globl far + .type far, %function +far: + bx lr + Index: lld/trunk/test/ELF/arm-thumb-thunk-symbols.s =================================================================== --- lld/trunk/test/ELF/arm-thumb-thunk-symbols.s +++ lld/trunk/test/ELF/arm-thumb-thunk-symbols.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-readobj --symbols %t2 | FileCheck %s // RUN: ld.lld --shared %t -o %t3 2>&1 Index: lld/trunk/test/ELF/arm-thunk-edgecase.s =================================================================== --- lld/trunk/test/ELF/arm-thunk-edgecase.s +++ lld/trunk/test/ELF/arm-thunk-edgecase.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: echo "SECTIONS { \ // RUN: .text_armfunc 0x1000 : { *(.text_armfunc) } \ // RUN: .text_thumbfunc 0x11010 : { *(.text_thumbfunc) } \ Index: lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s =================================================================== --- lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s +++ lld/trunk/test/ELF/arm-thunk-linkerscript-dotexpr.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ // RUN: .text_low : { *(.text_low) *(.text_low2) . = . + 0x2000000 ; *(.text_high) *(.text_high2) } \ Index: lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s =================================================================== --- lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s +++ lld/trunk/test/ELF/arm-thunk-linkerscript-orphan.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -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) } \ Index: lld/trunk/test/ELF/arm-thunk-linkerscript.s =================================================================== --- lld/trunk/test/ELF/arm-thunk-linkerscript.s +++ lld/trunk/test/ELF/arm-thunk-linkerscript.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ // RUN: .text_low : { *(.text_low) *(.text_low2) } \ Index: lld/trunk/test/ELF/arm-thunk-re-add.s =================================================================== --- lld/trunk/test/ELF/arm-thunk-re-add.s +++ lld/trunk/test/ELF/arm-thunk-re-add.s @@ -1,5 +1,5 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -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 Index: lld/trunk/test/ELF/arm-v5-reloc-error.s =================================================================== --- lld/trunk/test/ELF/arm-v5-reloc-error.s +++ lld/trunk/test/ELF/arm-v5-reloc-error.s @@ -0,0 +1,31 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-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: not ld.lld --script %t.script %t -o %t2 2>&1 | FileCheck %s + +// CHECK: error: relocation R_ARM_THM_JUMP24 to far not supported for Armv5 or Armv6 targets + +// Lie about our build attributes. Our triple is armv7a-linux-gnueabi but +// we are claiming to be Armv5. This can also happen with llvm-mc when we +// don't have any .eabi_attribute directives in the file or the +// --arm-add-build-attributes command line isn't used to add them from the +// triple. + .eabi_attribute 6, 5 // Tag_cpu_arch 5 = v5TEJ + .thumb + .syntax unified + .section .text_low, "ax", %progbits + .thumb + .globl _start + .type _start, %function +_start: + b.w far // Will produce relocation not supported in Armv5. + + .section .text_high, "ax", %progbits + .globl far + .type far, %function +far: + bx lr