29 changes: 22 additions & 7 deletions lld/test/ELF/arm-bl-v6.s
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -22,18 +25,28 @@ _start:
bl thumbfunc
bx lr

// CHECK-ARM1: Disassembly of section .text:
// CHECK-ARM1-NEXT: _start:
// CHECK-ARM1-NEXT: 11000: 00 00 00 fa blx #0 <thumbfunc>
// CHECK-ARM1-NEXT: 11004: 1e ff 2f e1 bx lr
.thumb
.section .text.2, "ax", %progbits
.globl thumbfunc
.type thumbfunc,%function
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

Expand All @@ -47,3 +60,5 @@ thumbfunc:
.type farthumbfunc,%function
farthumbfunc:
bx lr
// CHECK-THUMB2: farthumbfunc:
// CHECK-THUMB2-NEXT: 612000: 70 47 bx lr
1 change: 0 additions & 1 deletion lld/test/ELF/arm-blx-v4t.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions lld/test/ELF/arm-branch-rangethunk.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions lld/test/ELF/arm-branch-undef-weak-plt-thunk.s
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-long-thunk-converge.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions lld/test/ELF/arm-thumb-branch-rangethunk.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thumb-interwork-shared.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thumb-interwork-thunk-range.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
66 changes: 66 additions & 0 deletions lld/test/ELF/arm-thumb-interwork-thunk-v5.s
Original file line number Diff line number Diff line change
@@ -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 <thumb_func>
// CHECK-ARM-NEXT: 11008: 00 00 00 fa blx #0 <thumb_func>
// 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 <thumb_func>
// CHECK-ARM-PI-NEXT: 1008: 00 00 00 fa blx #0 <thumb_func>
// 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
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thumb-interwork-thunk.s
Original file line number Diff line number Diff line change
@@ -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) } \
Expand Down
39 changes: 39 additions & 0 deletions lld/test/ELF/arm-thumb-nov6thunk.s
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thumb-thunk-symbols.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thunk-edgecase.s
Original file line number Diff line number Diff line change
@@ -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) } \
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thunk-linkerscript-dotexpr.s
Original file line number Diff line number Diff line change
@@ -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) } \
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thunk-linkerscript-orphan.s
Original file line number Diff line number Diff line change
@@ -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) } \
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thunk-linkerscript.s
Original file line number Diff line number Diff line change
@@ -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) } \
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/arm-thunk-re-add.s
Original file line number Diff line number Diff line change
@@ -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
Expand Down
31 changes: 31 additions & 0 deletions lld/test/ELF/arm-v5-reloc-error.s
Original file line number Diff line number Diff line change
@@ -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