diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -199,17 +199,46 @@ void addSymbols(ThunkSection &isec) override; }; +// Implementations of Thunks for v4. BLX is not supported, and loads +// will not invoke Arm/Thumb state changes. +class ARMV4PILongBXThunk final : public ARMThunk { +public: + ARMV4PILongBXThunk(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; +}; + class ARMV4PILongThunk final : public ARMThunk { public: ARMV4PILongThunk(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 ThumbV4PILongBXThunk final : public ThumbThunk { +public: + ThumbV4PILongBXThunk(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; }; -// Implementations of Thunks for v4. BLX is not supported, and loads -// will not invoke Arm/Thumb state changes. +class ThumbV4PILongThunk final : public ThumbThunk { +public: + ThumbV4PILongThunk(Symbol &dest, int64_t addend) + : ThumbThunk(dest, addend) {} + + uint32_t sizeLong() override { return 20; } + void writeLong(uint8_t *buf) override; + void addSymbols(ThunkSection &isec) override; +}; + class ARMV4ABSLongBXThunk final : public ARMThunk { public: ARMV4ABSLongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {} @@ -788,7 +817,7 @@ addSymbol("$d", STT_NOTYPE, 12, isec); } -void ARMV4PILongThunk::writeLong(uint8_t *buf) { +void ARMV4PILongBXThunk::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 @@ -801,13 +830,77 @@ target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12); } +void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__ARMv4PILongBXThunk_" + destination.getName()), + STT_FUNC, 0, isec); + addSymbol("$a", STT_NOTYPE, 0, isec); + addSymbol("$d", STT_NOTYPE, 12, isec); +} + +void ARMV4PILongThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x00, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc] ; L2 + 0x0c, 0xf0, 0x8f, 0xe0, // L1: add pc, pc, r12 + 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 + 8, 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, 8, isec); +} + +void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x78, 0x47, // P: bx pc + 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc + 0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L2 + 0x0f, 0xf0, 0x8c, 0xe0, // L1: add pc, r12, pc + 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 - 16); +} + +void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__Thumbv4PILongBXThunk_" + 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 ThumbV4PILongThunk::writeLong(uint8_t *buf) { + const uint8_t data[] = { + 0x78, 0x47, // P: bx pc + 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc + 0x04, 0xc0, 0x9f, 0xe5, // 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 + 16, R_ARM_REL32, s - p - 16); +} + +void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) { + addSymbol(saver().save("__Thumbv4PILongThunk_" + destination.getName()), + STT_FUNC, 1, isec); + addSymbol("$t", STT_NOTYPE, 0, isec); + addSymbol("$a", STT_NOTYPE, 4, isec); + addSymbol("$d", STT_NOTYPE, 16, 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(); @@ -1155,17 +1248,18 @@ 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 + if (config->picThunk && thumb_target) + return make(s, a); + if (config->picThunk && !thumb_target) return make(s, a); if (thumb_target) return make(s, a); return make(s, a); case R_ARM_THM_CALL: - if (config->picThunk && !thumb_target) - fatal("PIC relocations across state change not supported for Armv4T"); if (config->picThunk && thumb_target) - return make(s, a); + return make(s, a); + if (config->picThunk && !thumb_target) + return make(s, a); if (thumb_target) return make(s, a); return make(s, a); @@ -1187,7 +1281,7 @@ case R_ARM_CALL: case R_ARM_THM_CALL: if (config->picThunk) - return make(s, a); + return make(s, a); return make(s, a); } fatal("relocation " + toString(reloc) + " to " + toString(s) + diff --git a/lld/test/ELF/arm-bl-v4.s b/lld/test/ELF/arm-bl-v4.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/arm-bl-v4.s @@ -0,0 +1,83 @@ +// REQUIRES: arm +// RUN: rm -rf %t && split-file %s %t +// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv4-none-linux-gnueabi %t/a.s -o %t/a.o +// RUN: ld.lld %t/a.o --script %t/far.lds -o %t/a-far +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4-none-linux-gnueabi %t/a-far | FileCheck %s --check-prefixes=FAR +// RUN: ld.lld %t/a.o --script %t/near.lds -o %t/a-near +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4-none-linux-gnueabi %t/a-near | FileCheck %s --check-prefixes=NEAR +// RUN: ld.lld %t/a.o -pie --script %t/far.lds -o %t/a-far-pie +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4-none-linux-gnueabi %t/a-far-pie | FileCheck %s --check-prefixes=FAR-PIE +// RUN: ld.lld %t/a.o -pie --script %t/near.lds -o %t/a-near-pie +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4-none-linux-gnueabi %t/a-near-pie | FileCheck %s --check-prefixes=NEAR + +/// On Armv4 there is no blx instruction so long branch/exchange looks slightly +/// different. + +#--- a.s + .text + .syntax unified + .cpu arm7tdmi + + .section .low, "ax", %progbits + .arm + .globl _start + .type _start,%function + .p2align 2 +_start: + bl target + mov pc, lr + +// FAR-LABEL: <_start>: +// FAR-NEXT: 1000000: bl 0x1000008 <__ARMv5LongLdrPcThunk_target> @ imm = #0 +// FAR-NEXT: mov pc, lr +// FAR-EMPTY: +// FAR-NEXT: <__ARMv5LongLdrPcThunk_target>: +// FAR-NEXT: 1000008: ldr pc, [pc, #-4] @ 0x100000c <__ARMv5LongLdrPcThunk_target+0x4> +// FAR-EMPTY: +// FAR-NEXT: <$d>: +// FAR-NEXT: 100000c: 00 00 00 06 .word 0x06000000 + +// FAR-PIE-LABEL: <_start>: +// FAR-PIE-NEXT: 1000000: bl 0x1000008 <__ARMv4PILongThunk_target> @ imm = #0 +// FAR-PIE-NEXT: mov pc, lr +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <__ARMv4PILongThunk_target>: +// FAR-PIE-NEXT: 1000008: ldr r12, [pc] @ 0x1000010 <__ARMv4PILongThunk_target+0x8> +// FAR-PIE-NEXT: add pc, pc, r12 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$d>: +// FAR-PIE-NEXT: 1000010: ec ff ff 04 .word 0x04ffffec +// FAR-PIE-EMPTY: + +// NEAR-LABEL: <_start>: +// NEAR-NEXT: 1000000: bl 0x1000008 @ imm = #0 +// NEAR-NEXT: mov pc, lr + +.section .high, "ax", %progbits + .arm + .globl target + .type target,%function +target: + mov pc, lr + +// FAR-LABEL: : +// FAR-NEXT: 6000000: mov pc, lr + +// FAR-PIE-LABEL: : +// FAR-PIE-NEXT: 6000000: mov pc, lr + +// NEAR-LABEL: : +// NEAR-LABEL: 1000008: mov pc, lr + +#--- far.lds +SECTIONS { + . = SIZEOF_HEADERS; + .low 0x01000000 : { *(.low) } + .high 0x06000000 : { *(.high) } +} + +#--- near.lds +SECTIONS { + . = SIZEOF_HEADERS; + .all 0x01000000 : { *(.low) *(.high) } +} diff --git a/lld/test/ELF/arm-bl-v4t.s b/lld/test/ELF/arm-bl-v4t.s --- a/lld/test/ELF/arm-bl-v4t.s +++ b/lld/test/ELF/arm-bl-v4t.s @@ -5,6 +5,10 @@ // RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-far | FileCheck %s --check-prefixes=FAR // RUN: ld.lld %t/a.o --script %t/near.lds -o %t/a-near // RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-near | FileCheck %s --check-prefixes=NEAR +// RUN: ld.lld %t/a.o -pie --script %t/far.lds -o %t/a-far-pie +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-far-pie | FileCheck %s --check-prefixes=FAR-PIE +// RUN: ld.lld %t/a.o -pie --script %t/near.lds -o %t/a-near-pie +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-near-pie | FileCheck %s --check-prefixes=NEAR /// On Armv4T there is no blx instruction so long branch/exchange looks slightly /// different. @@ -57,6 +61,34 @@ // FAR-NEXT: <$d>: // FAR-NEXT: 1000024: 05 00 00 06 .word 0x06000005 +// FAR-PIE-LABEL: <_start>: +// FAR-PIE-NEXT: 1000000: bl 0x1000010 <__ARMv4PILongThunk_target> @ imm = #8 +// FAR-PIE-NEXT: bx lr +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: : +// FAR-PIE-NEXT: 1000008: bl 0x100001c <__Thumbv4PILongThunk_thumb_target> @ imm = #16 +// FAR-PIE-NEXT: bx lr +// FAR-PIE-NEXT: bmi 0xffffba @ imm = #-88 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <__ARMv4PILongThunk_target>: +// FAR-PIE-NEXT: 1000010: ldr r12, [pc] @ 0x1000018 <__ARMv4PILongThunk_target+0x8> +// FAR-PIE-NEXT: add pc, pc, r12 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$d>: +// FAR-PIE-NEXT: 1000018: e4 ff ff 04 .word 0x04ffffe4 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <__Thumbv4PILongThunk_thumb_target>: +// FAR-PIE-NEXT: 100001c: bx pc +// FAR-PIE-NEXT: b 0x100001c <__Thumbv4PILongThunk_thumb_target> @ imm = #-6 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$a>: +// FAR-PIE-NEXT: 1000020: ldr r12, [pc, #4] @ 0x100002c <__Thumbv4PILongThunk_thumb_target+0x10> +// FAR-PIE-NEXT: add r12, pc, r12 +// FAR-PIE-NEXT: bx r12 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$d>: +// FAR-PIE-NEXT: 100002c: d9 ff ff 04 .word 0x04ffffd9 + // NEAR-LABEL: <_start>: // NEAR-NEXT: 1000000: bl 0x100000c @ imm = #4 // NEAR-NEXT: bx lr @@ -84,6 +116,12 @@ // FAR-LABEL: : // FAR-NEXT: 6000004: bx lr +// FAR-PIE-LABEL: : +// FAR-PIE-NEXT: 6000000: bx lr +// FAR-PIE-EMPTY: +// FAR-PIE-LABEL: : +// FAR-PIE-NEXT: 6000004: bx lr + // NEAR-LABEL: : // NEAR-LABEL: 100000e: bx lr // NEAR-EMPTY: diff --git a/lld/test/ELF/arm-bx-v4t.s b/lld/test/ELF/arm-bx-v4t.s --- a/lld/test/ELF/arm-bx-v4t.s +++ b/lld/test/ELF/arm-bx-v4t.s @@ -5,6 +5,10 @@ // RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-far | FileCheck %s --check-prefixes=FAR // RUN: ld.lld %t/a.o --script %t/near.lds -o %t/a-near // RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-near | FileCheck %s --check-prefixes=NEAR +// RUN: ld.lld %t/a.o -pie --script %t/far.lds -o %t/a-far-pie +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-far-pie | FileCheck %s --check-prefixes=FAR-PIE +// RUN: ld.lld %t/a.o -pie --script %t/near.lds -o %t/a-near-pie +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn --triple=armv4t-none-linux-gnueabi %t/a-near-pie | FileCheck %s --check-prefixes=NEAR-PIE /// On Arm v4t there is no blx instruction so all interworking must go via /// a thunk. @@ -45,6 +49,29 @@ // NEAR-NEXT: <$d>: // NEAR-NEXT: 1000010: 15 00 00 01 .word 0x01000015 +// FAR-PIE-LABEL: <_start>: +// FAR-PIE-NEXT: 1000000: bl 0x1000008 <__ARMv4PILongBXThunk_target> @ imm = #0 +// FAR-PIE-NEXT: bx lr +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <__ARMv4PILongBXThunk_target>: +// FAR-PIE-NEXT: 1000008: ldr r12, [pc, #4] @ 0x1000014 <__ARMv4PILongBXThunk_target+0xc> +// FAR-PIE-NEXT: add r12, pc, r12 +// FAR-PIE-NEXT: bx r12 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$d>: +// FAR-PIE-NEXT: 1000014: ed ff ff 04 .word 0x04ffffed + +// NEAR-PIE-LABEL: <_start>: +// NEAR-PIE-NEXT: 1000000: bl 0x1000008 <__ARMv4PILongBXThunk_target> @ imm = #0 +// NEAR-PIE-NEXT: bx lr +// NEAR-PIE-EMPTY: +// NEAR-PIE-NEXT: <__ARMv4PILongBXThunk_target>: +// NEAR-PIE-NEXT: 1000008: ldr r12, [pc, #4] @ 0x1000014 <__ARMv4PILongBXThunk_target+0xc> +// NEAR-PIE-NEXT: add r12, pc, r12 +// NEAR-PIE-NEXT: bx r12 +// NEAR-PIE-EMPTY: +// NEAR-PIE-NEXT: <$d>: +// NEAR-PIE-NEXT: 1000014: 05 00 00 00 .word 0x00000005 .section .high, "ax", %progbits .thumb @@ -71,12 +98,12 @@ // NEAR-LABEL: : // NEAR-NEXT: 1000014: bl 0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #4 -// NEAR-NEXT: 1000018: bx lr -// NEAR-NEXT: 100001a: bmi 0xffffc6 @ imm = #-88 +// NEAR-NEXT: bx lr +// NEAR-NEXT: bmi 0xffffc6 @ imm = #-88 // NEAR-EMPTY: // NEAR-NEXT: <__Thumbv4ABSLongBXThunk__start>: // NEAR-NEXT: 100001c: bx pc -// NEAR-NEXT: 100001e: b 0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #-6 +// NEAR-NEXT: b 0x100001c <__Thumbv4ABSLongBXThunk__start> @ imm = #-6 // NEAR-EMPTY: // NEAR-NEXT: <$a>: // NEAR-NEXT: 1000020: ldr pc, [pc, #-4] @ 0x1000024 <__Thumbv4ABSLongBXThunk__start+0x8> @@ -84,6 +111,38 @@ // NEAR-NEXT: <$d>: // NEAR-NEXT: 1000024: 00 00 00 01 .word 0x01000000 +// FAR-PIE-LABEL: : +// FAR-PIE-NEXT: 6000000: bl 0x6000008 <__Thumbv4PILongBXThunk__start> @ imm = #4 +// FAR-PIE-NEXT: bx lr +// FAR-PIE-NEXT: bmi 0x5ffffb2 <__ARMv4PILongBXThunk_target+0x4ffffaa> @ imm = #-88 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <__Thumbv4PILongBXThunk__start>: +// FAR-PIE-NEXT: 6000008: bx pc +// FAR-PIE-NEXT: b 0x6000008 <__Thumbv4PILongBXThunk__start> @ imm = #-6 +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$a>: +// FAR-PIE-NEXT: 600000c: ldr r12, [pc] @ 0x6000014 <__Thumbv4PILongBXThunk__start+0xc> +// FAR-PIE-NEXT: add pc, r12, pc +// FAR-PIE-EMPTY: +// FAR-PIE-NEXT: <$d>: +// FAR-PIE-NEXT: 6000014: e8 ff ff fa .word 0xfaffffe8 + +// NEAR-PIE-LABEL: : +// NEAR-PIE-NEXT: 1000018: bl 0x1000020 <__Thumbv4PILongBXThunk__start> @ imm = #4 +// NEAR-PIE-NEXT: bx lr +// NEAR-PIE-NEXT: bmi 0xffffca @ imm = #-88 +// NEAR-PIE-EMPTY: +// NEAR-PIE-NEXT: <__Thumbv4PILongBXThunk__start>: +// NEAR-PIE-NEXT: 1000020: bx pc +// NEAR-PIE-NEXT: b 0x1000020 <__Thumbv4PILongBXThunk__start> @ imm = #-6 +// NEAR-PIE-EMPTY: +// NEAR-PIE-NEXT: <$a>: +// NEAR-PIE-NEXT: 1000024: ldr r12, [pc] @ 0x100002c <__Thumbv4PILongBXThunk__start+0xc> +// NEAR-PIE-NEXT: add pc, r12, pc +// NEAR-PIE-EMPTY: +// NEAR-PIE-NEXT: <$d>: +// NEAR-PIE-NEXT: 100002c: d0 ff ff ff .word 0xffffffd0 + #--- far.lds SECTIONS { . = SIZEOF_HEADERS; 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 @@ -41,7 +41,7 @@ // CHECK-NEXT: 21018: 11 10 02 00 .word 0x00021011 // CHECK-PI: <_start>: -// CHECK-PI-NEXT: 11000: ea000003 b 0x11014 <__ARMv4PILongThunk_thumb_func> +// CHECK-PI-NEXT: 11000: ea000003 b 0x11014 <__ARMv4PILongBXThunk_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: <__ARMv4PILongThunk_thumb_func>: +// CHECK-PI: <__ARMv4PILongBXThunk_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 <__ARMv4PILongThunk_preemptible>: +// CHECK: 0070000c <__ARMv4PILongBXThunk_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 <__ARMv4PILongThunk_preemptible> +// CHECK-CALL: 80000c: blx 0x70000c <__ARMv4PILongBXThunk_preemptible> .balign 2 .globl preemptible .type preemptible, %function