Skip to content

Commit 4f38ab2

Browse files
committed
[LLD][ELF][ARM] Do not insert interworking thunks for non STT_FUNC symbols
ELF for the ARM architecture requires linkers to provide interworking for symbols that are of type STT_FUNC. Interworking for other symbols must be encoded directly in the object file. LLD was always providing interworking, regardless of the symbol type, this breaks some programs that have branches from Thumb state targeting STT_NOTYPE symbols that have bit 0 clear, but they are in fact internal labels in a Thumb function. LLD treats these symbols as ARM and inserts a transition to Arm. This fixes the problem for in range branches, R_ARM_JUMP24, R_ARM_THM_JUMP24 and R_ARM_THM_JUMP19. This is expected to be the vast majority of problem cases as branching to an internal label close to the function. There is at least one follow up patch required. - R_ARM_CALL and R_ARM_THM_CALL may do interworking via BL/BLX substitution. In theory range-extension thunks can be altered to not change state when the symbol type is not STT_FUNC. I will need to check with ld.bfd to see if this is the case in practice. Fixes (part of) ClangBuiltLinux/linux#773 Differential Revision: https://reviews.llvm.org/D73474
1 parent 3238b03 commit 4f38ab2

File tree

4 files changed

+130
-4
lines changed

4 files changed

+130
-4
lines changed

lld/ELF/Arch/ARM.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
277277
case R_ARM_PLT32:
278278
case R_ARM_JUMP24:
279279
// Source is ARM, all PLT entries are ARM so no interworking required.
280-
// Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
281-
if (expr == R_PC && ((s.getVA() & 1) == 1))
280+
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb).
281+
if (s.isFunc() && expr == R_PC && (s.getVA() & 1))
282282
return true;
283283
LLVM_FALLTHROUGH;
284284
case R_ARM_CALL: {
@@ -288,8 +288,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
288288
case R_ARM_THM_JUMP19:
289289
case R_ARM_THM_JUMP24:
290290
// Source is Thumb, all PLT entries are ARM so interworking is required.
291-
// Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
292-
if (expr == R_PLT_PC || ((s.getVA() & 1) == 0))
291+
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM).
292+
if (expr == R_PLT_PC || (s.isFunc() && (s.getVA() & 1) == 0))
293293
return true;
294294
LLVM_FALLTHROUGH;
295295
case R_ARM_THM_CALL: {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// REQUIRES: arm
2+
// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o %s
3+
// RUN: ld.lld %t.o -o %t
4+
// RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d --no-show-raw-insn %t
5+
6+
/// Non-preemptible ifuncs are called via a PLT entry which is always Arm
7+
/// state, expect the ARM callers to go direct to the PLT entry, Thumb
8+
/// branches are indirected via state change thunks, the bl is changed to blx.
9+
10+
.syntax unified
11+
.text
12+
.balign 0x1000
13+
.type foo STT_GNU_IFUNC
14+
.globl foo
15+
foo:
16+
bx lr
17+
18+
.section .text.1, "ax", %progbits
19+
.arm
20+
.global _start
21+
_start:
22+
b foo
23+
bl foo
24+
25+
.section .text.2, "ax", %progbits
26+
.thumb
27+
.global thumb_caller
28+
thumb_caller:
29+
b foo
30+
b.w foo
31+
bl foo
32+
33+
// CHECK: 00012004 _start:
34+
// CHECK-NEXT: b #36
35+
// CHECK-NEXT: bl #32
36+
37+
// CHECK: 0001200c thumb_caller:
38+
// CHECK-NEXT: b.w #8
39+
// CHECK-NEXT: b.w #4
40+
// CHECK-NEXT: blx #24
41+
42+
// CHECK: 00012018 __Thumbv7ABSLongThunk_foo:
43+
// CHECK-NEXT: movw r12, #8240
44+
// CHECK-NEXT: movt r12, #1
45+
// CHECK-NEXT: bx r12
46+
47+
// CHECK: Disassembly of section .iplt:
48+
49+
// CHECK: 00012030 $a:
50+
// CHECK-NEXT: add r12, pc, #0, #12
51+
// CHECK-NEXT: add r12, r12, #4096
52+
// CHECK-NEXT: ldr pc, [r12, #8]!
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// REQUIRES: arm
2+
// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o %s
3+
// RUN: ld.lld %t.o -o %t
4+
// RUN: llvm-objdump --no-show-raw-insn -d %t | FileCheck %s
5+
6+
.syntax unified
7+
.section .arm_target, "ax", %progbits
8+
.balign 0x1000
9+
.arm
10+
arm_func_with_notype:
11+
.type arm_func_with_explicit_notype, %notype
12+
arm_func_with_explicit_notype:
13+
bx lr
14+
15+
.section .thumb_target, "ax", %progbits
16+
.balign 4
17+
.thumb
18+
thumb_func_with_notype:
19+
.type thumb_func_with_explicit_notype, %notype
20+
thumb_func_with_explicit_notype:
21+
bx lr
22+
23+
/// All the symbols that are targets of the branch relocations do not have
24+
/// type STT_FUNC. LLD should not insert interworking thunks as non STT_FUNC
25+
/// symbols have no state information, the ABI assumes the user has manually
26+
/// done the interworking.
27+
.section .arm_caller, "ax", %progbits
28+
.balign 4
29+
.arm
30+
.global _start
31+
_start:
32+
b .arm_target
33+
b arm_func_with_notype
34+
b arm_func_with_explicit_notype
35+
b .thumb_target
36+
b thumb_func_with_notype
37+
b thumb_func_with_explicit_notype
38+
39+
.section .thumb_caller, "ax", %progbits
40+
.thumb
41+
.balign 4
42+
b.w .arm_target
43+
b.w arm_func_with_notype
44+
b.w arm_func_with_explicit_notype
45+
b.w .thumb_target
46+
b.w thumb_func_with_notype
47+
b.w thumb_func_with_explicit_notype
48+
beq.w .arm_target
49+
beq.w arm_func_with_notype
50+
beq.w arm_func_with_explicit_notype
51+
beq.w .thumb_target
52+
beq.w thumb_func_with_notype
53+
beq.w thumb_func_with_explicit_notype
54+
55+
// CHECK: 00012008 _start:
56+
// CHECK-NEXT: 12008: b #-16
57+
// CHECK-NEXT: 1200c: b #-20
58+
// CHECK-NEXT: 12010: b #-24
59+
// CHECK-NEXT: 12014: b #-24
60+
// CHECK-NEXT: 12018: b #-28
61+
// CHECK-NEXT: 1201c: b #-32
62+
// CHECK: 12020: b.w #-36
63+
// CHECK-NEXT: 12024: b.w #-40
64+
// CHECK-NEXT: 12028: b.w #-44
65+
// CHECK-NEXT: 1202c: b.w #-44
66+
// CHECK-NEXT: 12030: b.w #-48
67+
// CHECK-NEXT: 12034: b.w #-52
68+
// CHECK-NEXT: 12038: beq.w #-60
69+
// CHECK-NEXT: 1203c: beq.w #-64
70+
// CHECK-NEXT: 12040: beq.w #-68
71+
// CHECK-NEXT: 12044: beq.w #-68
72+
// CHECK-NEXT: 12048: beq.w #-72
73+
// CHECK-NEXT: 1204c: beq.w #-76

lld/test/ELF/arm-thunk-edgecase.s

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
.arm
1919
.section .text_armfunc, "ax", %progbits
2020
.globl armfunc
21+
.type armfunc, %function
2122
armfunc:
2223
b thumbfunc
2324

0 commit comments

Comments
 (0)