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 @@ -277,8 +277,8 @@ case R_ARM_PLT32: case R_ARM_JUMP24: // Source is ARM, all PLT entries are ARM so no interworking required. - // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). - if (expr == R_PC && ((s.getVA() & 1) == 1)) + // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb). + if (s.isFunc() && expr == R_PC && (s.getVA() & 1)) return true; LLVM_FALLTHROUGH; case R_ARM_CALL: { @@ -288,8 +288,8 @@ case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. - // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). - if (expr == R_PLT_PC || ((s.getVA() & 1) == 0)) + // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM). + if (expr == R_PLT_PC || (s.isFunc() && (s.getVA() & 1) == 0)) return true; LLVM_FALLTHROUGH; case R_ARM_THM_CALL: { diff --git a/lld/test/ELF/arm-thumb-interwork-ifunc.s b/lld/test/ELF/arm-thumb-interwork-ifunc.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/arm-thumb-interwork-ifunc.s @@ -0,0 +1,52 @@ +// REQUIRES: arm +// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d --no-show-raw-insn %t + +/// Non-preemptible ifuncs are called via a PLT entry which is always Arm +/// state, expect the ARM callers to go direct to the PLT entry, Thumb +/// branches are indirected via state change thunks, the bl is changed to blx. + + .syntax unified + .text + .balign 0x1000 + .type foo STT_GNU_IFUNC + .globl foo +foo: + bx lr + + .section .text.1, "ax", %progbits + .arm + .global _start +_start: + b foo + bl foo + + .section .text.2, "ax", %progbits + .thumb + .global thumb_caller +thumb_caller: + b foo + b.w foo + bl foo + +// CHECK: 00012004 _start: +// CHECK-NEXT: b #36 +// CHECK-NEXT: bl #32 + +// CHECK: 0001200c thumb_caller: +// CHECK-NEXT: b.w #8 +// CHECK-NEXT: b.w #4 +// CHECK-NEXT: blx #24 + +// CHECK: 00012018 __Thumbv7ABSLongThunk_foo: +// CHECK-NEXT: movw r12, #8240 +// CHECK-NEXT: movt r12, #1 +// CHECK-NEXT: bx r12 + +// CHECK: Disassembly of section .iplt: + +// CHECK: 00012030 $a: +// CHECK-NEXT: add r12, pc, #0, #12 +// CHECK-NEXT: add r12, r12, #4096 +// CHECK-NEXT: ldr pc, [r12, #8]! diff --git a/lld/test/ELF/arm-thumb-interwork-notfunc.s b/lld/test/ELF/arm-thumb-interwork-notfunc.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/arm-thumb-interwork-notfunc.s @@ -0,0 +1,73 @@ +// REQUIRES: arm +// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump --no-show-raw-insn -d %t | FileCheck %s + +.syntax unified +.section .arm_target, "ax", %progbits +.balign 0x1000 +.arm +arm_func_with_notype: +.type arm_func_with_explicit_notype, %notype +arm_func_with_explicit_notype: + bx lr + +.section .thumb_target, "ax", %progbits +.balign 4 +.thumb +thumb_func_with_notype: +.type thumb_func_with_explicit_notype, %notype +thumb_func_with_explicit_notype: + bx lr + +/// All the symbols that are targets of the branch relocations do not have +/// type STT_FUNC. LLD should not insert interworking thunks as non STT_FUNC +/// symbols have no state information, the ABI assumes the user has manually +/// done the interworking. +.section .arm_caller, "ax", %progbits +.balign 4 +.arm +.global _start +_start: + b .arm_target + b arm_func_with_notype + b arm_func_with_explicit_notype + b .thumb_target + b thumb_func_with_notype + b thumb_func_with_explicit_notype + + .section .thumb_caller, "ax", %progbits + .thumb + .balign 4 + b.w .arm_target + b.w arm_func_with_notype + b.w arm_func_with_explicit_notype + b.w .thumb_target + b.w thumb_func_with_notype + b.w thumb_func_with_explicit_notype + beq.w .arm_target + beq.w arm_func_with_notype + beq.w arm_func_with_explicit_notype + beq.w .thumb_target + beq.w thumb_func_with_notype + beq.w thumb_func_with_explicit_notype + +// CHECK: 00012008 _start: +// CHECK-NEXT: 12008: b #-16 +// CHECK-NEXT: 1200c: b #-20 +// CHECK-NEXT: 12010: b #-24 +// CHECK-NEXT: 12014: b #-24 +// CHECK-NEXT: 12018: b #-28 +// CHECK-NEXT: 1201c: b #-32 +// CHECK: 12020: b.w #-36 +// CHECK-NEXT: 12024: b.w #-40 +// CHECK-NEXT: 12028: b.w #-44 +// CHECK-NEXT: 1202c: b.w #-44 +// CHECK-NEXT: 12030: b.w #-48 +// CHECK-NEXT: 12034: b.w #-52 +// CHECK-NEXT: 12038: beq.w #-60 +// CHECK-NEXT: 1203c: beq.w #-64 +// CHECK-NEXT: 12040: beq.w #-68 +// CHECK-NEXT: 12044: beq.w #-68 +// CHECK-NEXT: 12048: beq.w #-72 +// CHECK-NEXT: 1204c: beq.w #-76 diff --git a/lld/test/ELF/arm-thunk-edgecase.s b/lld/test/ELF/arm-thunk-edgecase.s --- a/lld/test/ELF/arm-thunk-edgecase.s +++ b/lld/test/ELF/arm-thunk-edgecase.s @@ -18,6 +18,7 @@ .arm .section .text_armfunc, "ax", %progbits .globl armfunc +.type armfunc, %function armfunc: b thumbfunc