Index: test/ELF/arm-thumb-condbranch-thunk.s =================================================================== --- /dev/null +++ test/ELF/arm-thumb-condbranch-thunk.s @@ -0,0 +1,117 @@ +// 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=524288 -stop-address=524316 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s +// RUN: llvm-objdump -d %t2 -start-address=1048576 -stop-address=1048584 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s +// RUN: llvm-objdump -d %t2 -start-address=1572864 -stop-address=1572872 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s +// RUN: llvm-objdump -d %t2 -start-address=5242884 -stop-address=5242894 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s +// RUN: llvm-objdump -d %t2 -start-address=5767168 -stop-address=5767174 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK5 %s +// RUN: llvm-objdump -d %t2 -start-address=16777220 -stop-address=16777240 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s +// RUN: llvm-objdump -d %t2 -start-address=17825792 -stop-address=17825798 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s +// Test Range extension Thunks for the Thumb conditional branch instruction. +// This instruction only has a range of 1Mb whereas all the other Thumb wide +// Branch instructions have 16Mb range. We still place our pre-created Thunk +// Sections at 16Mb intervals as conditional branches to a target defined +// in a different section are rare. + .syntax unified +// Define a function aligned on a half megabyte boundary + .macro FUNCTION suff + .section .text.\suff\(), "ax", %progbits + .thumb + .balign 0x80000 + .globl tfunc\suff\() + .type tfunc\suff\(), %function +tfunc\suff\(): + bx lr + .endm + + .globl _start +_start: + FUNCTION 00 +// Long Range Thunk needed for 16Mb range branch, can reach pre-created Thunk +// Section + bl tfunc33 +// CHECK1: Disassembly of section .text: +// CHECK1-NEXT: tfunc00: +// CHECK1-NEXT: 80000: 70 47 bx lr +// CHECK1-NEXT: 80002: 7f f3 ff d7 bl #16252926 +// CHECK1: __Thumbv7ABSLongThunk_tfunc05: +// CHECK1-NEXT: 80008: 40 f2 01 0c movw r12, #1 +// CHECK1-NEXT: 8000c: c0 f2 30 0c movt r12, #48 +// CHECK1-NEXT: 80010: 60 47 bx r12 +// CHECK1: __Thumbv7ABSLongThunk_tfunc00: +// CHECK1-NEXT: 80012: 40 f2 01 0c movw r12, #1 +// CHECK1-NEXT: 80016: c0 f2 08 0c movt r12, #8 +// CHECK1-NEXT: 8001a: 60 47 bx r12 + FUNCTION 01 +// tfunc02 is within range of tfunc02 + beq.w tfunc02 +// tfunc05 is out of range, and we can't reach the pre-created Thunk Section +// create a new one. + bne.w tfunc05 +// CHECK2: tfunc01: +// CHECK2-NEXT: 100000: 70 47 bx lr +// CHECK2-NEXT: 100002: 3f f0 fd a7 beq.w #524282 +// CHECK2-NEXT: 100006: 7f f4 ff a7 bne.w #-524290 <__Thumbv7ABSLongThunk_tfunc05> + FUNCTION 02 +// We can reach the Thunk Section created for bne.w tfunc05 + bne.w tfunc05 + beq.w tfunc00 +// CHECK3: 180000: 70 47 bx lr +// CHECK3-NEXT: 180002: 40 f4 01 80 bne.w #-1048574 <__Thumbv7ABSLongThunk_tfunc05> +// CHECK3-NEXT: 180006: 00 f4 04 80 beq.w #-1048568 <__Thumbv7ABSLongThunk_tfunc00> + FUNCTION 03 + FUNCTION 04 + FUNCTION 05 + FUNCTION 06 + FUNCTION 07 + FUNCTION 08 + FUNCTION 09 +// CHECK4: __Thumbv7ABSLongThunk_tfunc03: +// CHECK4-NEXT: 500004: 40 f2 01 0c movw r12, #1 +// CHECK4-NEXT: 500008: c0 f2 20 0c movt r12, #32 +// CHECK4-NEXT: 50000c: 60 47 bx r12 + FUNCTION 10 +// We can't reach any Thunk Section, create a new one + beq.w tfunc03 +// CHECK5: tfunc10: +// CHECK5-NEXT: 580000: 70 47 bx lr +// CHECK5-NEXT: 580002: 3f f4 ff a7 beq.w #-524290 <__Thumbv7ABSLongThunk_tfunc03> + FUNCTION 11 + FUNCTION 12 + FUNCTION 13 + FUNCTION 14 + FUNCTION 15 + 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 + FUNCTION 29 + FUNCTION 30 + FUNCTION 31 +// CHECK6: __Thumbv7ABSLongThunk_tfunc33: +// CHECK6-NEXT: 1000004: 40 f2 01 0c movw r12, #1 +// CHECK6-NEXT: 1000008: c0 f2 10 1c movt r12, #272 +// CHECK6-NEXT: 100000c: 60 47 bx r12 +// CHECK6: __Thumbv7ABSLongThunk_tfunc00: +// CHECK6-NEXT: 100000e: 40 f2 01 0c movw r12, #1 +// CHECK6-NEXT: 1000012: c0 f2 08 0c movt r12, #8 +// CHECK6-NEXT: 1000016: 60 47 bx r12 + FUNCTION 32 + FUNCTION 33 + // We should be able to reach an existing ThunkSection. + b.w tfunc00 +// CHECK7: tfunc33: +// CHECK7-NEXT: 1100000: 70 47 bx lr +// CHECK7-NEXT: 1100002: 00 f7 04 b8 b.w #-1048568 <__Thumbv7ABSLongThunk_tfunc00> Index: test/ELF/arm-thumb-mix-range-thunk-os.s =================================================================== --- /dev/null +++ test/ELF/arm-thumb-mix-range-thunk-os.s @@ -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 +// 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 Index: test/ELF/arm-thumb-plt-range-thunk-os.s =================================================================== --- /dev/null +++ test/ELF/arm-thumb-plt-range-thunk-os.s @@ -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 Index: test/ELF/arm-thumb-range-thunk-os.s =================================================================== --- /dev/null +++ test/ELF/arm-thumb-range-thunk-os.s @@ -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 Index: test/ELF/arm-thunk-multipass.s =================================================================== --- /dev/null +++ test/ELF/arm-thunk-multipass.s @@ -0,0 +1,96 @@ +// 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=1048578 -stop-address=1048586 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s +// RUN: llvm-objdump -d %t2 -start-address=16777224 -stop-address=16777254 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s +// RUN: llvm-objdump -d %t2 -start-address=17825818 -stop-address=17825828 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s +// In this test case a branch that is in range and does not need its range +// extended can be pushed out of range by another Thunk, necessitating another +// pass + + .macro FUNCTION suff + .section .text.\suff\(), "ax", %progbits + .thumb + .balign 0x100000 + .globl tfunc\suff\() + .type tfunc\suff\(), %function +tfunc\suff\(): + bx lr + .endm + + FUNCTION 00 + .globl _start +_start: + bl target + b.w arm_target +// arm_target is in range but needs an interworking thunk +// CHECK1: _start: +// CHECK1-NEXT: 100002: 00 f3 06 d0 bl #15728652 +// CHECK1-NEXT: 100006: ff f2 ff 97 b.w #15728638 <__Thumbv7ABSLongThunk_arm_target> + nop + nop + nop + .globl target2 + .type target2, %function + nop + +target2: + FUNCTION 01 + FUNCTION 02 + FUNCTION 03 + FUNCTION 04 + FUNCTION 05 + FUNCTION 06 + FUNCTION 07 + FUNCTION 08 + FUNCTION 09 + FUNCTION 10 + FUNCTION 11 + FUNCTION 12 + FUNCTION 13 + FUNCTION 14 + FUNCTION 15 + + .section .text.16, "ax", %progbits + .arm + .globl arm_target + .type arm_target, %function +arm_target: + bx lr +// CHECK2: __Thumbv7ABSLongThunk_arm_target: +// CHECK2-NEXT: 1000008: 40 f2 02 0c movw r12, #2 +// CHECK2-NEXT: 100000c: c0 f2 00 1c movt r12, #256 +// CHECK2-NEXT: 1000010: 60 47 bx r12 +// CHECK2: __Thumbv7ABSLongThunk_target: +// CHECK2-NEXT: 1000012: 40 f2 1b 0c movw r12, #27 +// CHECK2-NEXT: 1000016: c0 f2 10 1c movt r12, #272 +// CHECK2-NEXT: 100001a: 60 47 bx r12 +// CHECK2: __Thumbv7ABSLongThunk_target2: +// CHECK2-NEXT: 100001c: 40 f2 13 0c movw r12, #19 +// CHECK2-NEXT: 1000020: c0 f2 10 0c movt r12, #16 +// CHECK2-NEXT: 1000024: 60 47 bx r12 + + .section .text.17, "ax", %progbits +// Just enough space so that bl target is in range if no extension thunks are +// generated. + + .space 0x100000 - 12 + + .section .text.18, "ax", %progbits + .thumb + .globl target + .type target, %function +// target is at maximum ARM branch range away from caller. +target: +// Similar case in the backwards direction + bl target2 + nop + nop + bx lr +// CHECK3: target: +// CHECK3-NEXT: 110001a: ff f6 ff ff bl #-1048578 +// CHECK3-NEXT: 110001e: 00 bf nop +// CHECK3-NEXT: 1100020: 00 bf nop +// CHECK3-NEXT: 1100022: 70 47 bx lr Index: test/ELF/arm-thunk-re-add.s =================================================================== --- /dev/null +++ test/ELF/arm-thunk-re-add.s @@ -0,0 +1,119 @@ +// 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=16777220 -stop-address=16777244 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s +// RUN: llvm-objdump -d %t.so -start-address=17825800 -stop-address=17825826 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s +// RUN: llvm-objdump -d %t.so -start-address=17825824 -stop-address=17825876 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s + +// A branch to a Thunk that we create on pass N, can drift out of range if +// other Thunks are added in between. In this case we must create a new Thunk +// for the branch that is in range. We also need to make sure that if the +// destination of the Thunk is in the PLT the new Thunk also targets the PLT + .syntax unified + .thumb + + .macro FUNCTION suff + .section .text.\suff\(), "ax", %progbits + .thumb + .balign 0x80000 + .globl tfunc\suff\() + .type tfunc\suff\(), %function +tfunc\suff\(): + bx lr + .endm + + .globl imported + .type imported, %function + .globl imported2 + .type imported2, %function + .globl imported3 + .type imported3, %function +.globl imported4 + .type imported4, %function + FUNCTION 00 + FUNCTION 01 + FUNCTION 02 + FUNCTION 03 + FUNCTION 04 + FUNCTION 05 + FUNCTION 06 + FUNCTION 07 + FUNCTION 08 + FUNCTION 09 + FUNCTION 10 + FUNCTION 11 + FUNCTION 12 + FUNCTION 13 + FUNCTION 14 + FUNCTION 15 + 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 + FUNCTION 29 + FUNCTION 30 + FUNCTION 31 +// Precreated Thunk Pool goes here +// CHECK1: 1000004: 40 f2 24 0c movw r12, #36 +// CHECK1-NEXT: 1000008: c0 f2 10 0c movt r12, #16 +// CHECK1-NEXT: 100000c: fc 44 add r12, pc +// CHECK1-NEXT: 100000e: 60 47 bx r12 +// CHECK1: __ThumbV7PILongThunk_imported2: +// CHECK1-NEXT: 1000010: 40 f2 28 0c movw r12, #40 +// CHECK1-NEXT: 1000014: c0 f2 10 0c movt r12, #16 +// CHECK1-NEXT: 1000018: fc 44 add r12, pc +// CHECK1-NEXT: 100001a: 60 47 bx r12 + + .section .text.32, "ax", %progbits + .space 0x80000 + .section .text.33, "ax", %progbits + .space 0x80000 - 0x14 + .section .text.34, "ax", %progbits + // Need a Thunk to the PLT entry, can use precreated ThunkSection + .globl callers + .type callers, %function +callers: + b.w imported + beq.w imported + b.w imported2 +// CHECK2: __ThumbV7PILongThunk_imported: +// CHECK2-NEXT: 1100008: 40 f2 20 0c movw r12, #32 +// CHECK2-NEXT: 110000c: c0 f2 00 0c movt r12, #0 +// CHECK2-NEXT: 1100010: fc 44 add r12, pc +// CHECK2-NEXT: 1100012: 60 47 bx r12 +// CHECK2: callers: +// CHECK2-NEXT: 1100014: ff f6 f6 bf b.w #-1048596 <__ThumbV7PILongThunk_imported> +// CHECK2-NEXT: 1100018: 3f f4 f6 af beq.w #-20 <__ThumbV7PILongThunk_imported> +// CHECK2-NEXT: 110001c: ff f6 f8 bf b.w #-1048592 <__ThumbV7PILongThunk_imported2> + +// CHECK3: Disassembly of section .plt: +// CHECK3-NEXT: $a: +// CHECK3-NEXT: 1100020: 04 e0 2d e5 str lr, [sp, #-4]! +// CHECK3-NEXT: 1100024: 04 e0 9f e5 ldr lr, [pc, #4] +// CHECK3-NEXT: 1100028: 0e e0 8f e0 add lr, pc, lr +// CHECK3-NEXT: 110002c: 08 f0 be e5 ldr pc, [lr, #8]! +// CHECK3: $d: +// CHECK3-NEXT: 1100030: d0 0f 00 00 .word 0x00000fd0 +// CHECK3: $a: +// CHECK3-NEXT: 1100034: 04 c0 9f e5 ldr r12, [pc, #4] +// CHECK3-NEXT: 1100038: 0f c0 8c e0 add r12, r12, pc +// CHECK3-NEXT: 110003c: 00 f0 9c e5 ldr pc, [r12] +// CHECK3: $d: +// CHECK3-NEXT: 1100040: cc 0f 00 00 .word 0x00000fcc +// CHECK3: $a: +// CHECK3-NEXT: 1100044: 04 c0 9f e5 ldr r12, [pc, #4] +// CHECK3-NEXT: 1100048: 0f c0 8c e0 add r12, r12, pc +// CHECK3-NEXT: 110004c: 00 f0 9c e5 ldr pc, [r12] +// CHECK3: $d: +// CHECK3-NEXT: 1100050: c0 0f 00 00 .word 0x00000fc0