diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -314,7 +314,8 @@ [[fallthrough]]; case R_ARM_CALL: { uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); - return !inBranchRange(type, branchAddr, dst + a); + return !inBranchRange(type, branchAddr, dst + a) || + (!config->armHasBlx && (s.getVA() & 1)); } case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: @@ -325,7 +326,8 @@ [[fallthrough]]; case R_ARM_THM_CALL: { uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA() : s.getVA(); - return !inBranchRange(type, branchAddr, dst + a); + return !inBranchRange(type, branchAddr, dst + a) || + (!config->armHasBlx && (s.getVA() & 1) == 0);; } } return false; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -2786,15 +2786,6 @@ config->imageBase = getImageBase(args); - if (config->emachine == EM_ARM) { - // FIXME: These warnings can be removed when lld only uses these features - // when the input objects have been compiled with an architecture that - // supports them. - if (config->armHasBlx == false) - warn("lld uses blx instruction, no object with architecture supporting " - "feature detected"); - } - // This adds a .comment section containing a version string. if (!config->relocatable) ctx.inputSections.push_back(createCommentSection()); diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -161,37 +161,67 @@ void addSymbols(ThunkSection &isec) override; }; -// Implementations of Thunks for older Arm architectures that do not support -// the movt/movw instructions. These thunks require at least Architecture v5 -// as used on processors such as the Arm926ej-s. There are no Thumb entry -// points as there is no Thumb branch instruction on these architecture that -// can result in a thunk -class ARMV5ABSLongThunk final : public ARMThunk { +// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted +class ThumbV6MABSLongThunk final : public ThumbThunk { public: - ARMV5ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {} + ThumbV6MABSLongThunk(Symbol &dest, int64_t addend) + : ThumbThunk(dest, addend) {} + + uint32_t sizeLong() override { return 12; } + void writeLong(uint8_t *buf) override; + void addSymbols(ThunkSection &isec) override; +}; + +class ThumbV6MPILongThunk final : public ThumbThunk { +public: + ThumbV6MPILongThunk(Symbol &dest, int64_t addend) + : ThumbThunk(dest, addend) {} + + uint32_t sizeLong() override { return 16; } + void writeLong(uint8_t *buf) override; + void addSymbols(ThunkSection &isec) override; +}; + +// Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and +// v6 support BLX to which BL instructions can be rewritten inline. There are no +// Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on +// these architecture that can result in a thunk. + +// LDR on v5 and v6 can switch processor state, so for v5 and v6, +// ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4 +// can also use this thunk, but only for Arm->Arm calls. +class ARMV5LongLdrPcThunk final : public ARMThunk { +public: + ARMV5LongLdrPcThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {} uint32_t sizeLong() override { return 8; } void writeLong(uint8_t *buf) override; void addSymbols(ThunkSection &isec) override; - bool isCompatibleWith(const InputSection &isec, - const Relocation &rel) const override; }; -class ARMV5PILongThunk final : public ARMThunk { +class ARMV4PILongThunk final : public ARMThunk { public: - ARMV5PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {} + ARMV4PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {} uint32_t sizeLong() override { return 16; } void writeLong(uint8_t *buf) override; void addSymbols(ThunkSection &isec) override; - bool isCompatibleWith(const InputSection &isec, - const Relocation &rel) const override; }; -// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted -class ThumbV6MABSLongThunk final : public ThumbThunk { +// Implementations of Thunks for v4. BLX is not supported, and loads +// will not invoke Arm/Thumb state changes. +class ARMV4ABSLongBXThunk final : public ARMThunk { public: - ThumbV6MABSLongThunk(Symbol &dest, int64_t addend) + ARMV4ABSLongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {} + + uint32_t sizeLong() override { return 12; } + void writeLong(uint8_t *buf) override; + void addSymbols(ThunkSection &isec) override; +}; + +class ThumbV4ABSLongBXThunk final : public ThumbThunk { +public: + ThumbV4ABSLongBXThunk(Symbol &dest, int64_t addend) : ThumbThunk(dest, addend) {} uint32_t sizeLong() override { return 12; } @@ -199,9 +229,9 @@ void addSymbols(ThunkSection &isec) override; }; -class ThumbV6MPILongThunk final : public ThumbThunk { +class ThumbV4ABSLongThunk final : public ThumbThunk { public: - ThumbV6MPILongThunk(Symbol &dest, int64_t addend) + ThumbV4ABSLongThunk(Symbol &dest, int64_t addend) : ThumbThunk(dest, addend) {} uint32_t sizeLong() override { return 16; } @@ -504,6 +534,10 @@ bool ARMThunk::isCompatibleWith(const InputSection &isec, const Relocation &rel) const { + // v4T does not have BLX, so also deny R_ARM_THM_CALL + if (!config->armHasBlx && rel.type == R_ARM_THM_CALL) + return false; + // Thumb branch relocations can't use BLX return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24; } @@ -542,6 +576,10 @@ bool ThumbThunk::isCompatibleWith(const InputSection &isec, const Relocation &rel) const { + // v4T does not have BLX, so also deny R_ARM_CALL + if (!config->armHasBlx && rel.type == R_ARM_CALL) + return false; + // ARM branch relocations can't use BLX return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32; } @@ -624,54 +662,6 @@ addSymbol("$t", STT_NOTYPE, 0, isec); } -void ARMV5ABSLongThunk::writeLong(uint8_t *buf) { - const uint8_t data[] = { - 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 - 0x00, 0x00, 0x00, 0x00, // L1: .word S - }; - memcpy(buf, data, sizeof(data)); - target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination)); -} - -void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ARMv5ABSLongThunk_" + destination.getName()), - STT_FUNC, 0, isec); - addSymbol("$a", STT_NOTYPE, 0, isec); - addSymbol("$d", STT_NOTYPE, 4, isec); -} - -bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec, - const Relocation &rel) const { - // Thumb branch relocations can't use BLX - return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24; -} - -void ARMV5PILongThunk::writeLong(uint8_t *buf) { - const uint8_t data[] = { - 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2 - 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip - 0x1c, 0xff, 0x2f, 0xe1, // bx ip - 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8) - }; - uint64_t s = getARMThunkDestVA(destination); - uint64_t p = getThunkTargetSym()->getVA() & ~0x1; - memcpy(buf, data, sizeof(data)); - target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12); -} - -void ARMV5PILongThunk::addSymbols(ThunkSection &isec) { - addSymbol(saver().save("__ARMV5PILongThunk_" + destination.getName()), - STT_FUNC, 0, isec); - addSymbol("$a", STT_NOTYPE, 0, isec); - addSymbol("$d", STT_NOTYPE, 12, isec); -} - -bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec, - const Relocation &rel) const { - // Thumb branch relocations can't use BLX - return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24; -} - void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) { // Most Thumb instructions cannot access the high registers r8 - r15. As the // only register we can corrupt is r12 we must instead spill a low register @@ -722,6 +712,101 @@ addSymbol("$d", STT_NOTYPE, 12, isec); } +void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1 + 0x00, 0x00, 0x00, 0x00, // L1: .word S + }; + memcpy(buf, data, sizeof(data)); + target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination)); +} + +void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__ARMv5LongLdrPcThunk_" + destination.getName()), + STT_FUNC, 0, isec); + addSymbol("$a", STT_NOTYPE, 0, isec); + addSymbol("$d", STT_NOTYPE, 4, isec); +} + +void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1 + 0x1c, 0xff, 0x2f, 0xe1, // bx r12 + 0x00, 0x00, 0x00, 0x00, // L1: .word S + }; + + memcpy(buf, data, sizeof(data)); + target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination)); +} + +void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__ARMv4ABSLongBXThunk_" + destination.getName()), + STT_FUNC, 0, isec); + addSymbol("$a", STT_NOTYPE, 0, isec); + addSymbol("$d", STT_NOTYPE, 8, isec); +} + +void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x78, 0x47, // bx pc + 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc + 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4] + 0x00, 0x00, 0x00, 0x00, // L1: .word S + }; + + memcpy(buf, data, sizeof(data)); + target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination)); +} + +void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__Thumbv4ABSLongBXThunk_" + destination.getName()), + STT_FUNC, 1, isec); + addSymbol("$t", STT_NOTYPE, 0, isec); + addSymbol("$a", STT_NOTYPE, 4, isec); + addSymbol("$d", STT_NOTYPE, 8, isec); +} + +void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x78, 0x47, // bx pc + 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc + 0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1 + 0x1c, 0xff, 0x2f, 0xe1, // bx r12 + 0x00, 0x00, 0x00, 0x00, // L1: .word S + }; + + memcpy(buf, data, sizeof(data)); + target->relocateNoSym(buf + 12, R_ARM_ABS32, getARMThunkDestVA(destination)); +} + +void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__Thumbv4ABSLongThunk_" + destination.getName()), + STT_FUNC, 1, isec); + addSymbol("$t", STT_NOTYPE, 0, isec); + addSymbol("$a", STT_NOTYPE, 4, isec); + addSymbol("$d", STT_NOTYPE, 12, isec); +} + +void ARMV4PILongThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2 + 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip + 0x1c, 0xff, 0x2f, 0xe1, // bx ip + 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8) + }; + uint64_t s = getARMThunkDestVA(destination); + uint64_t p = getThunkTargetSym()->getVA() & ~0x1; + memcpy(buf, data, sizeof(data)); + target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12); +} + +void ARMV4PILongThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__ARMv4PILongThunk_" + destination.getName()), + STT_FUNC, 0, isec); + addSymbol("$a", STT_NOTYPE, 0, isec); + addSymbol("$d", STT_NOTYPE, 12, isec); +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *buf) { uint64_t s = destination.getVA(); @@ -1051,12 +1136,51 @@ return make(s, a); } -// Creates a thunk for Thumb-ARM interworking. -// Arm Architectures v5 and v6 do not support Thumb2 technology. This means +// Creates a thunk for long branches or Thumb-ARM interworking. +// Arm Architectures v4t does not support Thumb2 technology, and does not +// support BLX or LDR Arm/Thumb state switching. This means that +// - MOVT and MOVW instructions cannot be used. +// - We can't rewrite BL in place to BLX. We will need thunks. +// +// TODO: Support PIC interworking thunks for V4T. +// TODO: More efficient PIC non-interworking thunks for V4T. +// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for +// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state). +static Thunk *addThunkArmv4(RelType reloc, Symbol &s, int64_t a) { + bool thumb_target = s.getVA(a) & 1; + + switch (reloc) { + case R_ARM_PC24: + case R_ARM_PLT32: + case R_ARM_JUMP24: + case R_ARM_CALL: + if (config->picThunk) + // can be used for both Arm->Arm and Arm->Thumb + return make(s, a); + else if (thumb_target) + return make(s, a); + else + return make(s, a); + case R_ARM_THM_CALL: + if (config->picThunk && !thumb_target) + fatal("PIC relocations across state change not supported for Armv4T"); + else if (config->picThunk && thumb_target) + return make(s, a); + else if (!thumb_target) + return make(s, a); + else + return make(s, a); + } + fatal("relocation " + toString(reloc) + " to " + toString(s) + + " not supported for Armv4 or Armv4T target"); +} + +// Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6. +// Arm Architectures v5 and v6 do not support Thumb2 technology. This means that // - MOVT and MOVW instructions cannot be used // - Only Thumb relocation that can generate a Thunk is a BL, this can always // be transformed into a BLX -static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s, int64_t a) { +static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) { switch (reloc) { case R_ARM_PC24: case R_ARM_PLT32: @@ -1064,8 +1188,8 @@ case R_ARM_CALL: case R_ARM_THM_CALL: if (config->picThunk) - return make(s, a); - return make(s, a); + return make(s, a); + return make(s, a); } fatal("relocation " + toString(reloc) + " to " + toString(s) + " not supported for Armv5 or Armv6 targets"); @@ -1108,9 +1232,11 @@ // of the input objects. InputFiles.cpp contains the mapping from ARM // architecture to flag. if (!config->armHasMovtMovw) { - if (!config->armJ1J2BranchEncoding) - return addThunkPreArmv7(reloc, s, a); - return addThunkV6M(reloc, s, a); + if (config->armJ1J2BranchEncoding) + return addThunkV6M(reloc, s, a); + else if (config->armHasBlx) + return addThunkArmv5v6(reloc, s, a); + return addThunkArmv4(reloc, s, a); } switch (reloc) { diff --git a/lld/test/ELF/arm-bl-v4t.s b/lld/test/ELF/arm-bl-v4t.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/arm-bl-v4t.s @@ -0,0 +1,91 @@ +// REQUIRES: arm +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv4t-none-linux-gnueabi %s -o %t +// RUN: echo "SECTIONS { \ +// RUN: . = SIZEOF_HEADERS; \ +// RUN: .low 0x01000000 : { *(.low) } \ +// RUN: .high 0x06000000 : { *(.high) } } " > %t1.script +// RUN: ld.lld %t --script %t1.script -o %t2 +// RUN: llvm-objdump -d --triple=armv4t-none-linux-gnueabi %t2 | FileCheck %s --check-prefixes=FAR +// RUN: echo "SECTIONS { \ +// RUN: . = SIZEOF_HEADERS; \ +// RUN: .low 0x01000000 : { *(.low) } \ +// RUN: .high 0x03500000 : { *(.high) } } " > %t3.script +// RUN: ld.lld %t --script %t3.script -o %t4 +// RON: llvm-objdump -d --triple=armv4t-none-linux-gnueabi %t4 | FileCheck %s --check-prefixes=MEDIUM +// RUN: echo "SECTIONS { \ +// RUN: . = SIZEOF_HEADERS; \ +// RUN: .all 0x01000000 : { *(.low) *(.high) } } " > %t5.script +// RUN: ld.lld %t --script %t5.script -o %t6 +// RUN: llvm-objdump -d --triple=armv4t-none-linux-gnueabi %t6 | FileCheck %s --check-prefixes=NEAR + +// On Armv4T there is no blx instruction so long branch/exchange looks slightly +// different. + + .text + .syntax unified + .cpu arm7tdmi + + .section .low, "ax", %progbits + .arm + .globl _start + .type _start,%function + .p2align 2 +_start: + bl target + bx lr + + .thumb + .globl thumb_start + .type thumb_start,%function + .p2align 2 +thumb_start: + bl thumb_target + bx lr + +// FAR: 01000000 <_start>: +// FAR-NEXT: 1000000: eb000002 bl 0x1000010 <__ARMv5LongLdrPcThunk_target> @ imm = #0x8 +// FAR-NEXT: 1000004: e12fff1e bx lr +// FAR-EMPTY: +// FAR-NEXT: 01000008 : +// FAR-NEXT: 1000008: f000 f806 bl 0x1000018 <__Thumbv4ABSLongThunk_thumb_target> @ imm = #0xc +// FAR-NEXT: 100000c: 4770 bx lr +// FAR-NEXT: 100000e: d4d4 bmi 0xffffba @ imm = #-0x58 +// FAR-EMPTY: +// FAR-NEXT: 01000010 <__ARMv5LongLdrPcThunk_target>: +// FAR-NEXT: 1000010: e51ff004 ldr pc, [pc, #-0x4] @ 0x1000014 <__ARMv5LongLdrPcThunk_target+0x4> +// FAR-EMPTY: +// FAR-NEXT: 01000014 <$d>: +// FAR-NEXT: 1000014: 00 00 00 06 .word 0x06000000 +// FAR-EMPTY: +// FAR-NEXT: 01000018 <__Thumbv4ABSLongThunk_thumb_target>: +// FAR-NEXT: 1000018: 4778 bx pc +// FAR-NEXT: 100001a: e7fd b 0x1000018 <__Thumbv4ABSLongThunk_thumb_target> @ imm = #-0x6 +// FAR-EMPTY: +// FAR-NEXT: 0100001c <$a>: +// FAR-NEXT: 100001c: e59fc000 ldr r12, [pc] @ 0x1000024 <__Thumbv4ABSLongThunk_thumb_target+0xc> +// FAR-NEXT: 1000020: e12fff1c bx r12 +// FAR-EMPTY: +// FAR-NEXT: 01000024 <$d>: +// FAR-NEXT: 1000024: 05 00 00 06 .word 0x06000005 + +// NEAR: 01000000 <_start>: +// NEAR-NEXT: 1000000: eb000001 bl 0x100000c @ imm = #0x4 +// NEAR-NEXT: 1000004: e12fff1e bx lr +// NEAR-EMPTY: +// NEAR-NEXT: 01000008 : +// NEAR-NEXT: 1000008: f000 f803 bl 0x1000012 @ imm = #0x6 +// NEAR-NEXT: 100000c: 4770 bx lr + + +.section .high, "ax", %progbits + .arm + .globl target + .type target,%function +target: + bx lr + +.thumb + .globl thumb_target + .type thumb_target,%function +thumb_target: + bx lr diff --git a/lld/test/ELF/arm-bl-v6.s b/lld/test/ELF/arm-bl-v6.s --- a/lld/test/ELF/arm-bl-v6.s +++ b/lld/test/ELF/arm-bl-v6.s @@ -38,13 +38,13 @@ bl farthumbfunc // CHECK-THUMB1: : -// CHECK-THUMB1-NEXT: 21008: f200 e800 blx 0x22100c <__ARMv5ABSLongThunk_farthumbfunc> +// CHECK-THUMB1-NEXT: 21008: f200 e800 blx 0x22100c <__ARMv5LongLdrPcThunk_farthumbfunc> /// 6 Megabytes, enough to make farthumbfunc out of range of caller /// on a v6 Arm, but not on a v7 Arm. .section .text.3, "ax", %progbits .space 0x200000 -// CHECK-ARM2: <__ARMv5ABSLongThunk_farthumbfunc>: +// CHECK-ARM2: <__ARMv5LongLdrPcThunk_farthumbfunc>: // CHECK-ARM2-NEXT: 22100c: e51ff004 ldr pc, [pc, #-4] // CHECK-ARM2: <$d>: // CHECK-ARM2-NEXT: 221010: 01 20 62 00 .word 0x00622001 diff --git a/lld/test/ELF/arm-blx-v4t.s b/lld/test/ELF/arm-blx-v4t.s deleted file mode 100644 --- a/lld/test/ELF/arm-blx-v4t.s +++ /dev/null @@ -1,27 +0,0 @@ -// REQUIRES: arm -// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t -// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s - -// On Arm v4t there is no blx instruction so all interworking must go via -// a thunk. At present we don't support v4t so we give a warning for unsupported -// features. - -// CHECK: warning: lld uses blx instruction, no object with architecture supporting feature detected - - .text - .syntax unified - .cpu arm7tdmi - .arm - .globl _start - .type _start,%function - .p2align 2 -_start: - bl thumbfunc - bx lr - - .thumb - .section .text.2, "ax", %progbits - .globl thumbfunc - .type thumbfunc,%function -thumbfunc: - bx lr diff --git a/lld/test/ELF/arm-blx.s b/lld/test/ELF/arm-blx.s --- a/lld/test/ELF/arm-blx.s +++ b/lld/test/ELF/arm-blx.s @@ -1,6 +1,6 @@ // REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar // RUN: echo "SECTIONS { \ // RUN: . = 0xb4; \ // RUN: .callee1 : { *(.callee_low) } \ diff --git a/lld/test/ELF/arm-bx-v4t.s b/lld/test/ELF/arm-bx-v4t.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/arm-bx-v4t.s @@ -0,0 +1,84 @@ +// REQUIRES: arm +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv4t-none-linux-gnueabi %s -o %t +// RUN: echo "SECTIONS { \ +// RUN: . = SIZEOF_HEADERS; \ +// RUN: .low 0x01000000 : { *(.low) } \ +// RUN: .high 0x06000000 : { *(.high) } } " > %t1.script +// RUN: ld.lld %t --script %t1.script -o %t2 +// RUN: llvm-objdump -d --triple=armv4t-none-linux-gnueabi %t2 | FileCheck %s --check-prefixes=FAR +// RUN: echo "SECTIONS { \ +// RUN: . = SIZEOF_HEADERS; \ +// RUN: .all 0x01000000 : { *(.low) *(.high) } } " > %t3.script +// RUN: ld.lld %t --script %t3.script -o %t4 +// RUN: llvm-objdump -d --triple=armv4t-none-linux-gnueabi %t4 | FileCheck %s --check-prefixes=NEAR +// On Arm v4t there is no blx instruction so all interworking must go via +// a thunk. + + .text + .syntax unified + .cpu arm7tdmi + + .section .low, "ax", %progbits + .arm + .globl _start + .type _start,%function + .p2align 2 +_start: + bl target + bx lr +// FAR: 01000000 <_start>: +// FAR-NEXT: 1000000: eb000000 bl 0x1000008 <__ARMv4ABSLongBXThunk_target> @ imm = #0 +// FAR-NEXT: 1000004: e12fff1e bx lr +// FAR-EMPTY: +// FAR-NEXT: 01000008 <__ARMv4ABSLongBXThunk_target>: +// FAR-NEXT: 1000008: e59fc000 ldr r12, [pc] @ 0x1000010 <__ARMv4ABSLongBXThunk_target+0x8> +// FAR-NEXT: 100000c: e12fff1c bx r12 +// FAR-EMPTY: +// FAR-NEXT: 01000010 <$d>: +// FAR-NEXT: 1000010: 01 00 00 06 .word 0x06000001 + +// NEAR: 01000000 <_start>: +// NEAR-NEXT: 1000000: eb000000 bl 0x1000008 <__ARMv4ABSLongBXThunk_target> @ imm = #0 +// NEAR-NEXT: 1000004: e12fff1e bx lr +// NEAR-EMPTY: +// NEAR-NEXT: 01000008 <__ARMv4ABSLongBXThunk_target>: +// NEAR-NEXT: 1000008: e59fc000 ldr r12, [pc] @ 0x1000010 <__ARMv4ABSLongBXThunk_target+0x8> +// NEAR-NEXT: 100000c: e12fff1c bx r12 +// NEAR-EMPTY: +// NEAR-NEXT: 01000010 <$d>: +// NEAR-NEXT: 1000010: 15 00 00 01 .word 0x01000015 + + +.section .high, "ax", %progbits +.thumb + .globl target + .type target,%function +target: + bl _start + bx lr +// FAR: 06000000 : +// FAR-NEXT: 6000000: f000 f802 bl 0x6000008 <__Thumbv4ABSLongBXThunk__start> @ imm = #0x4 +// FAR-NEXT: 6000004: 4770 bx lr + +// FAR: 06000008 <__Thumbv4ABSLongBXThunk__start>: +// FAR-NEXT: 6000008: 4778 bx pc +// FAR-NEXT: 600000a: e7fd b 0x6000008 <__Thumbv4ABSLongBXThunk__start> @ imm = #-0x6 +// FAR-EMPTY: +// FAR-NEXT: 0600000c <$a>: +// FAR-NEXT: 600000c: e51ff004 ldr pc, [pc, #-0x4] @ 0x6000010 <__Thumbv4ABSLongBXThunk__start+0x8> +// FAR-EMPTY: +// FAR-NEXT: 06000010 <$d>: +// FAR-NEXT: 6000010: 00 00 00 01 .word 0x01000000 + +// NEAR: 01000014 : +// NEAR-NEXT: 1000014: f000 f802 bl 0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #0x4 +// NEAR-NEXT: 1000018: 4770 bx lr +// NEAR: 0100001c <__Thumbv4ABSLongBXThunk__start>: +// NEAR-NEXT: 100001c: 4778 bx pc +// NEAR-NEXT: 100001e: e7fd b 0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #-0x6 +// NEAR-EMPTY: +// NEAR-NEXT: 01000020 <$a>: +// NEAR-NEXT: 1000020: e51ff004 ldr pc, [pc, #-0x4] @ 0x1000024 <__Thumbv4ABSLongBXThunk__start+0x8> +// NEAR-EMPTY: +// NEAR-NEXT: 01000024 <$d>: +// NEAR-NEXT: 1000024: 00 00 00 01 .word 0x01000000 diff --git a/lld/test/ELF/arm-thumb-interwork-thunk-v5.s b/lld/test/ELF/arm-thumb-interwork-thunk-v5.s --- a/lld/test/ELF/arm-thumb-interwork-thunk-v5.s +++ b/lld/test/ELF/arm-thumb-interwork-thunk-v5.s @@ -27,7 +27,7 @@ bx lr // CHECK: <_start>: -// CHECK-NEXT: 21000: ea000003 b 0x21014 <__ARMv5ABSLongThunk_thumb_func> +// CHECK-NEXT: 21000: ea000003 b 0x21014 <__ARMv5LongLdrPcThunk_thumb_func> // CHECK-NEXT: 21004: fa000001 blx 0x21010 // CHECK-NEXT: 21008: fa000000 blx 0x21010 // CHECK-NEXT: 2100c: e12fff1e bx lr @@ -35,13 +35,13 @@ // CHECK: : // CHECK-NEXT: 21010: 4770 bx lr -// CHECK: <__ARMv5ABSLongThunk_thumb_func>: +// CHECK: <__ARMv5LongLdrPcThunk_thumb_func>: // CHECK-NEXT: 21014: e51ff004 ldr pc, [pc, #-4] // CHECK: <$d>: // CHECK-NEXT: 21018: 11 10 02 00 .word 0x00021011 // CHECK-PI: <_start>: -// CHECK-PI-NEXT: 11000: ea000003 b 0x11014 <__ARMV5PILongThunk_thumb_func> +// CHECK-PI-NEXT: 11000: ea000003 b 0x11014 <__ARMv4PILongThunk_thumb_func> // CHECK-PI-NEXT: 11004: fa000001 blx 0x11010 // CHECK-PI-NEXT: 11008: fa000000 blx 0x11010 // CHECK-PI-NEXT: 1100c: e12fff1e bx lr @@ -49,7 +49,7 @@ // CHECK-PI: : // CHECK-PI-NEXT: 11010: 4770 bx lr -// CHECK-PI: <__ARMV5PILongThunk_thumb_func>: +// CHECK-PI: <__ARMv4PILongThunk_thumb_func>: // CHECK-PI-NEXT: 11014: e59fc004 ldr r12, [pc, #4] // CHECK-PI-NEXT: 11018: e08fc00c add r12, pc, r12 // CHECK-PI-NEXT: 1101c: e12fff1c bx r12 diff --git a/lld/test/ELF/arm-thunk-multipass-plt.s b/lld/test/ELF/arm-thunk-multipass-plt.s --- a/lld/test/ELF/arm-thunk-multipass-plt.s +++ b/lld/test/ELF/arm-thunk-multipass-plt.s @@ -42,7 +42,7 @@ .section .text.07, "ax", %progbits .space (1024 * 1024) /// 0xd00040 = preemptible@plt -// CHECK: 0070000c <__ARMV5PILongThunk_preemptible>: +// CHECK: 0070000c <__ARMv4PILongThunk_preemptible>: // CHECK-NEXT: 70000c: b 0xd00040 .section .text.08, "ax", %progbits @@ -52,7 +52,7 @@ .balign 2 bl preemptible bl preemptible2 -// CHECK-CALL: 80000c: blx 0x70000c <__ARMV5PILongThunk_preemptible> +// CHECK-CALL: 80000c: blx 0x70000c <__ARMv4PILongThunk_preemptible> .balign 2 .globl preemptible .type preemptible, %function