Skip to content

Commit c03fdd3

Browse files
committed
[ELF] Fix the branch range computation when reusing a thunk
Notation: dst is `t->getThunkTargetSym()->getVA()` On AArch64, when `src-0x8000000-r_addend <= dst < src-0x8000000`, the condition `target->inBranchRange(rel.type, src, rel.sym->getVA(rel.addend))` may incorrectly consider a thunk reusable. `rel.addend = -getPCBias(rel.type)` resets the addend to 0 for AArch64/PPC and the zero addend is used by `rel.sym->getVA(rel.addend)` to check out-of-range relocations. See the test for a case this computation is wrong: `error: a.o:(.text_high+0x4): relocation R_AARCH64_JUMP26 out of range: -134217732 is not in [-134217728, 134217727]` I have seen a real world case with r_addend=19960. Reviewed By: peter.smith Differential Revision: https://reviews.llvm.org/D117734
1 parent 6997f4d commit c03fdd3

File tree

3 files changed

+104
-2
lines changed

3 files changed

+104
-2
lines changed

lld/ELF/Relocations.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,7 +2042,8 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
20422042
// out in the relocation addend. We compensate for the PC bias so that
20432043
// an Arm and Thumb relocation to the same destination get the same keyAddend,
20442044
// which is usually 0.
2045-
int64_t keyAddend = rel.addend + getPCBias(rel.type);
2045+
const int64_t pcBias = getPCBias(rel.type);
2046+
const int64_t keyAddend = rel.addend + pcBias;
20462047

20472048
// We use a ((section, offset), addend) pair to find the thunk position if
20482049
// possible so that we create only one thunk for aliased symbols or ICFed
@@ -2061,7 +2062,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
20612062
if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) &&
20622063
t->isCompatibleWith(*isec, rel) &&
20632064
target->inBranchRange(rel.type, src,
2064-
t->getThunkTargetSym()->getVA(rel.addend)))
2065+
t->getThunkTargetSym()->getVA(-pcBias)))
20652066
return std::make_pair(t, false);
20662067

20672068
// No existing compatible Thunk in range, create a new one

lld/test/ELF/aarch64-thunk-reuse.s

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# REQUIRES: aarch64
2+
# RUN: rm -rf %t && split-file %s %t
3+
# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/a.s -o %t/a.o
4+
# RUN: ld.lld -pie -T %t/lds %t/a.o -o %t/a
5+
# RUN: llvm-objdump -d --no-show-raw-insn %t/a | FileCheck %s
6+
7+
## We create a thunk for dest.
8+
# CHECK-LABEL: <mid>:
9+
# CHECK-NEXT: 8010008: b 0x801000c <__AArch64ADRPThunk_>
10+
# CHECK-EMPTY:
11+
# CHECK-NEXT: <__AArch64ADRPThunk_>:
12+
# CHECK-NEXT: 801000c: adrp x16, 0x10000
13+
# CHECK-NEXT: add x16, x16, #4
14+
# CHECK-NEXT: br x16
15+
16+
## The first instruction can reuse the thunk but the second can't.
17+
## If we reuse the thunk for b, we will get an "out of range" error.
18+
# CHECK-LABEL: <high>:
19+
# CHECK-NEXT: 1001000c: bl 0x801000c <__AArch64ADRPThunk_>
20+
# CHECK-NEXT: b 0x10010014 <__AArch64ADRPThunk_>
21+
# CHECK-EMPTY:
22+
# CHECK-NEXT: <__AArch64ADRPThunk_>:
23+
# CHECK-NEXT: 10010014: adrp x16, 0x10000
24+
# CHECK-NEXT: add x16, x16, #4
25+
# CHECK-NEXT: br x16
26+
27+
#--- a.s
28+
.section .text_low, "ax", %progbits
29+
.globl _start
30+
_start:
31+
nop
32+
dest:
33+
ret
34+
35+
.section .text_mid, "ax", %progbits
36+
mid:
37+
b dest
38+
39+
.section .text_high, "ax", %progbits
40+
high:
41+
bl dest
42+
b dest
43+
44+
#--- lds
45+
SECTIONS {
46+
.text_low 0x10000: { *(.text_low) }
47+
.text_mid 0x8010008 : { *(.text_mid) }
48+
.text_high 0x1001000c : { *(.text_high) }
49+
}

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# REQUIRES: arm
2+
# RUN: rm -rf %t && split-file %s %t
3+
# RUN: llvm-mc -filetype=obj -triple=armv7-a-none-eabi --arm-add-build-attributes %t/a.s -o %t/a.o
4+
# RUN: ld.lld -pie -T %t/lds %t/a.o -o %t/a
5+
# RUN: llvm-objdump -d --no-show-raw-insn %t/a | FileCheck %s
6+
7+
## We create a thunk for dest.
8+
# CHECK-LABEL: <mid>:
9+
# CHECK-NEXT: 2010004: b 0x2010008 <__ARMV7PILongThunk_dest>
10+
# CHECK-EMPTY:
11+
# CHECK-NEXT: <__ARMV7PILongThunk_dest>:
12+
# CHECK-NEXT: 2010008: movw r12, #65516
13+
# CHECK-NEXT: movt r12, #65023
14+
# CHECK-NEXT: add r12, r12, pc
15+
# CHECK-NEXT: bx r12
16+
17+
## The first instruction can reuse the thunk but the second can't.
18+
## If we reuse the thunk for b, we will get an "out of range" error.
19+
# CHECK-LABEL: <high>:
20+
# CHECK-NEXT: 4010000: bl 0x2010008 <__ARMV7PILongThunk_dest>
21+
# CHECK-NEXT: b 0x4010008 <__ARMV7PILongThunk_dest>
22+
# CHECK-EMPTY:
23+
# CHECK-NEXT: <__ARMV7PILongThunk_dest>:
24+
# CHECK-NEXT: 4010008: movw r12, #65516
25+
# CHECK-NEXT: movt r12, #64511
26+
# CHECK-NEXT: add r12, r12, pc
27+
# CHECK-NEXT: bx r12
28+
29+
#--- a.s
30+
.section .text_low, "ax", %progbits
31+
32+
.globl _start
33+
_start:
34+
nop
35+
dest:
36+
bx lr
37+
38+
.section .text_mid, "ax", %progbits
39+
mid:
40+
b dest
41+
42+
.section .text_high, "ax", %progbits
43+
high:
44+
bl dest
45+
b dest
46+
47+
#--- lds
48+
SECTIONS {
49+
.text_low 0x10000: { *(.text_low) }
50+
.text_mid 0x2010004 : { *(.text_mid) }
51+
.text_high 0x4010000 : { *(.text_high) }
52+
}

0 commit comments

Comments
 (0)