Skip to content

Commit 3cde1d8

Browse files
authored
[ELF] Handle relocations in synthetic .eh_frame with a non-zero offset within the output section (llvm#65966)
When the .eh_frame section is placed at a non-zero offset within its output section, the relocation value within .eh_frame are computed incorrectly. We had similar issue in .ARM.exidx section and it has been fixed already in https://reviews.llvm.org/D148033. While applying the relocation using S+A-P, the value of P (the location of the relocation) is getting wrong. P is: P = SecAddr + rel.offset, But SecAddr points to the starting address of the outputsection rather than the starting address of the eh frame section within that output section. This issue affects all targets which generates .eh_frame section. Hence fixing in all the corresponding targets it affecting.
1 parent 54be730 commit 3cde1d8

9 files changed

+226
-2
lines changed

lld/ELF/Arch/AArch64.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,8 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
770770
uint64_t secAddr = sec.getOutputSection()->addr;
771771
if (auto *s = dyn_cast<InputSection>(&sec))
772772
secAddr += s->outSecOff;
773+
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
774+
secAddr += ehIn->getParent()->outSecOff;
773775
AArch64Relaxer relaxer(sec.relocs());
774776
for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
775777
const Relocation &rel = sec.relocs()[i];

lld/ELF/Arch/PPC64.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,8 @@ void PPC64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
15631563
uint64_t secAddr = sec.getOutputSection()->addr;
15641564
if (auto *s = dyn_cast<InputSection>(&sec))
15651565
secAddr += s->outSecOff;
1566+
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
1567+
secAddr += ehIn->getParent()->outSecOff;
15661568
uint64_t lastPPCRelaxedRelocOff = -1;
15671569
for (const Relocation &rel : sec.relocs()) {
15681570
uint8_t *loc = buf + rel.offset;

lld/ELF/Arch/X86_64.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,8 @@ void X86_64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
989989
uint64_t secAddr = sec.getOutputSection()->addr;
990990
if (auto *s = dyn_cast<InputSection>(&sec))
991991
secAddr += s->outSecOff;
992+
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
993+
secAddr += ehIn->getParent()->outSecOff;
992994
for (const Relocation &rel : sec.relocs()) {
993995
if (rel.expr == R_NONE) // See deleteFallThruJmpInsn
994996
continue;

lld/ELF/SyntheticSections.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,13 +583,14 @@ static uint64_t readFdeAddr(uint8_t *buf, int size) {
583583
uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff,
584584
uint8_t enc) const {
585585
// The starting address to which this FDE applies is
586-
// stored at FDE + 8 byte.
586+
// stored at FDE + 8 byte. And this offset is within
587+
// the .eh_frame section.
587588
size_t off = fdeOff + 8;
588589
uint64_t addr = readFdeAddr(buf + off, enc & 0xf);
589590
if ((enc & 0x70) == DW_EH_PE_absptr)
590591
return addr;
591592
if ((enc & 0x70) == DW_EH_PE_pcrel)
592-
return addr + getParent()->addr + off;
593+
return addr + getParent()->addr + off + outSecOff;
593594
fatal("unknown FDE size relative encoding");
594595
}
595596

lld/ELF/Target.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ void TargetInfo::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
159159
uint64_t secAddr = sec.getOutputSection()->addr;
160160
if (auto *s = dyn_cast<InputSection>(&sec))
161161
secAddr += s->outSecOff;
162+
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
163+
secAddr += ehIn->getParent()->outSecOff;
162164
for (const Relocation &rel : sec.relocs()) {
163165
uint8_t *loc = buf + rel.offset;
164166
const uint64_t val = SignExtend64(
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// REQUIRES: aarch64
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
// RUN: llvm-mc -filetype=obj -triple=aarch64 a.s -o a.o
5+
// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
6+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
7+
// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
8+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
9+
10+
// NONZERO: {{[0-9]+}}: 0000000000000088 {{.*}} __eh_frame_start
11+
// NONZERO-NEXT: {{[0-9]+}}: 00000000000000b4 {{.*}} __eh_frame_end
12+
13+
// NONZERO: 0x00000088 10000000 00000000 017a5200 017c1e01
14+
// NONZERO-NEXT: 0x00000098 1b0c1f00 10000000 18000000 5cffffff
15+
// NONZERO-NEXT: 0x000000a8 04000000 00000000 00000000
16+
17+
// ZERO: {{[0-9]+}}: 0000000000000008 {{.*}} __eh_frame_start
18+
// ZERO-NEXT: {{[0-9]+}}: 0000000000000034 {{.*}} __eh_frame_end
19+
20+
// ZERO: 0x00000008 10000000 00000000 017a5200 017c1e01
21+
// ZERO-NEXT: 0x00000018 1b0c1f00 10000000 18000000 dcffffff
22+
// ZERO-NEXT: 0x00000028 04000000 00000000 00000000
23+
24+
//--- eh-frame-non-zero-offset.t
25+
SECTIONS {
26+
.text : { *(.text .text.*) }
27+
.eh_frame : {
28+
/* Padding within .eh_frame */
29+
. += 128;
30+
__eh_frame_start = .;
31+
*(.eh_frame) ;
32+
__eh_frame_end = .;
33+
}
34+
}
35+
36+
//--- eh-frame-zero-offset.t
37+
SECTIONS {
38+
.text : { *(.text .text.*) }
39+
.eh_frame : {
40+
__eh_frame_start = .;
41+
*(.eh_frame) ;
42+
__eh_frame_end = .;
43+
}
44+
}
45+
46+
//--- a.s
47+
.section .text.01, "ax",%progbits
48+
.global f1
49+
.type f1, %function
50+
f1:
51+
.cfi_startproc
52+
.space 4
53+
.cfi_endproc
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// REQUIRES: arm
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
// RUN: llvm-mc -filetype=obj -triple=arm a.s -o a.o
5+
// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
6+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
7+
// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
8+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
9+
10+
// NONZERO: {{[0-9]+}}: 00000084 {{.*}} __eh_frame_start
11+
// NONZERO-NEXT: {{[0-9]+}}: 000000b0 {{.*}} __eh_frame_end
12+
13+
// NONZERO: 0x00000084 10000000 00000000 017a5200 017c0e01
14+
// NONZERO-NEXT: 0x00000094 1b0c0d00 10000000 18000000 60ffffff
15+
// NONZERO-NEXT: 0x000000a4 04000000 00000000 00000000
16+
17+
// ZERO: {{[0-9]+}}: 00000004 {{.*}} __eh_frame_start
18+
// ZERO-NEXT: {{[0-9]+}}: 00000030 {{.*}} __eh_frame_end
19+
20+
// ZERO: 0x00000004 10000000 00000000 017a5200 017c0e01
21+
// ZERO-NEXT: 0x00000014 1b0c0d00 10000000 18000000 e0ffffff
22+
// ZERO-NEXT: 0x00000024 04000000 00000000 00000000
23+
24+
//--- eh-frame-non-zero-offset.t
25+
SECTIONS {
26+
.text : { *(.text .text.*) }
27+
.eh_frame : {
28+
/* Padding within .eh_frame */
29+
. += 128;
30+
__eh_frame_start = .;
31+
*(.eh_frame) ;
32+
__eh_frame_end = .;
33+
}
34+
}
35+
36+
//--- eh-frame-zero-offset.t
37+
SECTIONS {
38+
.text : { *(.text .text.*) }
39+
.eh_frame : {
40+
__eh_frame_start = .;
41+
*(.eh_frame) ;
42+
__eh_frame_end = .;
43+
}
44+
}
45+
46+
//--- a.s
47+
.section .text.01, "ax",%progbits
48+
.global f1
49+
.type f1, %function
50+
f1:
51+
.cfi_startproc
52+
.cfi_sections .eh_frame
53+
.space 4
54+
.cfi_endproc
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// REQUIRES: ppc
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
// RUN: llvm-mc -filetype=obj -triple=ppc64le a.s -o a.o
5+
// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
6+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
7+
// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
8+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
9+
10+
// NONZERO: {{[0-9]+}}: 0000000000000088 {{.*}} __eh_frame_start
11+
// NONZERO-NEXT: {{[0-9]+}}: 00000000000000b4 {{.*}} __eh_frame_end
12+
13+
// NONZERO: 0x00000088 10000000 00000000 017a5200 04784101
14+
// NONZERO-NEXT: 0x00000098 1b0c0100 10000000 18000000 5cffffff
15+
// NONZERO-NEXT: 0x000000a8 04000000 00000000 00000000
16+
17+
// ZERO: {{[0-9]+}}: 0000000000000008 {{.*}} __eh_frame_start
18+
// ZERO-NEXT: {{[0-9]+}}: 0000000000000034 {{.*}} __eh_frame_end
19+
20+
// ZERO: 0x00000008 10000000 00000000 017a5200 04784101
21+
// ZERO-NEXT: 0x00000018 1b0c0100 10000000 18000000 dcffffff
22+
// ZERO-NEXT: 0x00000028 04000000 00000000 00000000
23+
24+
//--- eh-frame-non-zero-offset.t
25+
SECTIONS {
26+
.text : { *(.text .text.*) }
27+
.eh_frame : {
28+
/* Padding within .eh_frame */
29+
. += 128;
30+
__eh_frame_start = .;
31+
*(.eh_frame) ;
32+
__eh_frame_end = .;
33+
}
34+
}
35+
36+
//--- eh-frame-zero-offset.t
37+
SECTIONS {
38+
.text : { *(.text .text.*) }
39+
.eh_frame : {
40+
__eh_frame_start = .;
41+
*(.eh_frame) ;
42+
__eh_frame_end = .;
43+
}
44+
}
45+
46+
//--- a.s
47+
.section .text.01, "ax",%progbits
48+
.global f1
49+
.type f1, %function
50+
f1:
51+
.cfi_startproc
52+
.space 4
53+
.cfi_endproc
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// REQUIRES: x86
2+
// RUN: rm -rf %t && split-file %s %t && cd %t
3+
4+
// RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
5+
// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
6+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
7+
// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
8+
// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
9+
10+
// NONZERO: {{[0-9]+}}: 0000000000000088 {{.*}} __eh_frame_start
11+
// NONZERO-NEXT: {{[0-9]+}}: 00000000000000bc {{.*}} __eh_frame_end
12+
13+
// NONZERO: 0x00000088 14000000 00000000 017a5200 01781001
14+
// NONZERO-NEXT: 0x00000098 1b0c0708 90010000 14000000 1c000000
15+
// NONZERO-NEXT: 0x000000a8 58ffffff 04000000 00000000 00000000
16+
// NONZERO-NEXT: 0x000000b8 00000000
17+
18+
// ZERO: {{[0-9]+}}: 0000000000000008 {{.*}} __eh_frame_start
19+
// ZERO-NEXT: {{[0-9]+}}: 000000000000003c {{.*}} __eh_frame_end
20+
21+
// ZERO: 0x00000008 14000000 00000000 017a5200 01781001
22+
// ZERO-NEXT: 0x00000018 1b0c0708 90010000 14000000 1c000000
23+
// ZERO-NEXT: 0x00000028 d8ffffff 04000000 00000000 00000000
24+
// ZERO-NEXT: 0x00000038 00000000
25+
26+
//--- eh-frame-non-zero-offset.t
27+
SECTIONS {
28+
.text : { *(.text .text.*) }
29+
.eh_frame : {
30+
/* Padding within .eh_frame */
31+
. += 128;
32+
__eh_frame_start = .;
33+
*(.eh_frame) ;
34+
__eh_frame_end = .;
35+
}
36+
}
37+
38+
//--- eh-frame-zero-offset.t
39+
SECTIONS {
40+
.text : { *(.text .text.*) }
41+
.eh_frame : {
42+
__eh_frame_start = .;
43+
*(.eh_frame) ;
44+
__eh_frame_end = .;
45+
}
46+
}
47+
48+
//--- a.s
49+
.section .text.01, "ax",%progbits
50+
.global f1
51+
.type f1, %function
52+
f1:
53+
.cfi_startproc
54+
.space 4
55+
.cfi_endproc

0 commit comments

Comments
 (0)