[Lldb-commits] [lldb] [ELF] Handle relocations in synthetic .eh_frame with a non-zero offset within the output section (PR #65966)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Oct 2 13:25:38 PDT 2023
https://github.com/simpal01 updated https://github.com/llvm/llvm-project/pull/65966
>From 43c156c679951cc3d827fdb7604e30aab658fd9a Mon Sep 17 00:00:00 2001
From: Simi Pallipurath <simi.pallipurath at arm.com>
Date: Mon, 11 Sep 2023 14:42:27 +0100
Subject: [PATCH 1/3] [LLD][AARCH64] lld incorrectly handles .eh_frame when it
has a non-zero offset within its output section.
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 AArch32 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.
---
lld/ELF/Arch/AArch64.cpp | 3 ++
lld/test/ELF/eh-frame-nonzero-offset.s | 55 ++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
create mode 100644 lld/test/ELF/eh-frame-nonzero-offset.s
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 174a0a3624f7765..09477141c777948 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -770,6 +770,9 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr;
if (auto *s = dyn_cast<InputSection>(&sec))
secAddr += s->outSecOff;
+ else if (auto *eh = dyn_cast<EhInputSection>(&sec))
+ if (InputSection *isec = eh->getParent())
+ secAddr += isec->outSecOff;
AArch64Relaxer relaxer(sec.relocs());
for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
const Relocation &rel = sec.relocs()[i];
diff --git a/lld/test/ELF/eh-frame-nonzero-offset.s b/lld/test/ELF/eh-frame-nonzero-offset.s
new file mode 100644
index 000000000000000..ef086fcf670d81b
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset.s
@@ -0,0 +1,55 @@
+// REQUIRES: aarch64
+// RUN: rm -rf %t && split-file %s %t
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64 %t/a.s -o %t/a.o
+// RUN: ld.lld %t/a.o -T %t/eh-frame-non-zero-offset.t -o %t/non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld %t/a.o -T %t/eh-frame-zero-offset.t -o %t/zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO: {{[0-9]+}}: 0000000000000080 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 00000000000000ac {{.*}} __eh_frame_end
+
+// NONZERO: 0x00000078 00000000 00000000 10000000 00000000
+// NONZERO-NEXT: 0x00000088 017a5200 017c1e01 1b0c1f00 10000000
+// NONZERO-NEXT: 0x00000098 18000000 64ffffff 08000000 00000000
+// NONZERO-NEXT: 0x000000a8 00000000
+
+// ZERO: {{[0-9]+}}: 0000000000000080 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 00000000000000ac {{.*}} __eh_frame_end
+
+// ZERO: 0x00000080 10000000 00000000 017a5200 017c1e01
+// ZERO-NEXT: 0x00000090 1b0c1f00 10000000 18000000 64ffffff
+// ZERO-NEXT: 0x000000a0 08000000 00000000 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : {
+ /* Alignment padding within .eh_frame */
+ . = ALIGN(128);
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : ALIGN(128) {
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- a.s
+.section .text.01, "ax",%progbits
+.global f1
+.type f1, %function
+f1:
+.cfi_startproc
+ nop
+ nop
+.cfi_endproc
>From bf78a2ee26fac6235f9cb32ced10ae7c92f4b579 Mon Sep 17 00:00:00 2001
From: Simi Pallipurath <simi.pallipurath at arm.com>
Date: Mon, 18 Sep 2023 19:50:56 +0100
Subject: [PATCH 2/3] fixup! [LLD][AARCH64] lld incorrectly handles .eh_frame
when it has a non-zero offset within its output section.
---
lld/ELF/Arch/AArch64.cpp | 7 ++-
lld/ELF/Arch/PPC64.cpp | 4 ++
lld/ELF/Arch/X86_64.cpp | 4 ++
lld/ELF/SyntheticSections.cpp | 7 ++-
lld/ELF/Target.cpp | 4 ++
...et.s => eh-frame-nonzero-offset-aarch64.s} | 0
lld/test/ELF/eh-frame-nonzero-offset-arm.s | 55 +++++++++++++++++++
lld/test/ELF/eh-frame-nonzero-offset-ppc.s | 54 ++++++++++++++++++
lld/test/ELF/eh-frame-nonzero-offset-x86.s | 54 ++++++++++++++++++
9 files changed, 185 insertions(+), 4 deletions(-)
rename lld/test/ELF/{eh-frame-nonzero-offset.s => eh-frame-nonzero-offset-aarch64.s} (100%)
create mode 100644 lld/test/ELF/eh-frame-nonzero-offset-arm.s
create mode 100644 lld/test/ELF/eh-frame-nonzero-offset-ppc.s
create mode 100644 lld/test/ELF/eh-frame-nonzero-offset-x86.s
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 09477141c777948..e7b98419d382583 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -770,9 +770,10 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr;
if (auto *s = dyn_cast<InputSection>(&sec))
secAddr += s->outSecOff;
- else if (auto *eh = dyn_cast<EhInputSection>(&sec))
- if (InputSection *isec = eh->getParent())
- secAddr += isec->outSecOff;
+ else if (auto *ehIn = dyn_cast<EhInputSection>(&sec)) {
+ SyntheticSection *ehFrame = ehIn->getParent();
+ secAddr += ehFrame->outSecOff;
+ }
AArch64Relaxer relaxer(sec.relocs());
for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
const Relocation &rel = sec.relocs()[i];
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index 969d9326a7fc962..6f2d4d8e46c5535 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -1563,6 +1563,10 @@ void PPC64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr;
if (auto *s = dyn_cast<InputSection>(&sec))
secAddr += s->outSecOff;
+ else if (auto *ehIn = dyn_cast<EhInputSection>(&sec)) {
+ SyntheticSection *ehFrame = ehIn->getParent();
+ secAddr += ehFrame->outSecOff;
+ }
uint64_t lastPPCRelaxedRelocOff = -1;
for (const Relocation &rel : sec.relocs()) {
uint8_t *loc = buf + rel.offset;
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 349ccd218a579e4..1fd9dd4f21944ba 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -989,6 +989,10 @@ void X86_64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr;
if (auto *s = dyn_cast<InputSection>(&sec))
secAddr += s->outSecOff;
+ else if (auto *ehIn = dyn_cast<EhInputSection>(&sec)) {
+ SyntheticSection *ehFrame = ehIn->getParent();
+ secAddr += ehFrame->outSecOff;
+ }
for (const Relocation &rel : sec.relocs()) {
if (rel.expr == R_NONE) // See deleteFallThruJmpInsn
continue;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index f412efa36480284..416ebdc266eaa82 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -583,9 +583,14 @@ static uint64_t readFdeAddr(uint8_t *buf, int size) {
uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff,
uint8_t enc) const {
// The starting address to which this FDE applies is
- // stored at FDE + 8 byte.
+ // stored at FDE + 8 byte. And this offset is within
+ // the .eh_frame section.
size_t off = fdeOff + 8;
uint64_t addr = readFdeAddr(buf + off, enc & 0xf);
+ // Adding outSecOff as finalizeAddressDependentContent()
+ // may have altered the corresponding outSecOff. This is
+ // required to get the correct PC relative offset.
+ off = off + outSecOff;
if ((enc & 0x70) == DW_EH_PE_absptr)
return addr;
if ((enc & 0x70) == DW_EH_PE_pcrel)
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 32bb2164a208b85..84f7b4844c2a34c 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -159,6 +159,10 @@ void TargetInfo::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
uint64_t secAddr = sec.getOutputSection()->addr;
if (auto *s = dyn_cast<InputSection>(&sec))
secAddr += s->outSecOff;
+ else if (auto *ehIn = dyn_cast<EhInputSection>(&sec)) {
+ SyntheticSection *ehFrame = ehIn->getParent();
+ secAddr += ehFrame->outSecOff;
+ }
for (const Relocation &rel : sec.relocs()) {
uint8_t *loc = buf + rel.offset;
const uint64_t val = SignExtend64(
diff --git a/lld/test/ELF/eh-frame-nonzero-offset.s b/lld/test/ELF/eh-frame-nonzero-offset-aarch64.s
similarity index 100%
rename from lld/test/ELF/eh-frame-nonzero-offset.s
rename to lld/test/ELF/eh-frame-nonzero-offset-aarch64.s
diff --git a/lld/test/ELF/eh-frame-nonzero-offset-arm.s b/lld/test/ELF/eh-frame-nonzero-offset-arm.s
new file mode 100644
index 000000000000000..2461c3c585edfd3
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-arm.s
@@ -0,0 +1,55 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t
+
+// RUN: llvm-mc -filetype=obj -triple=arm %t/a.s -o %t/a.o
+// RUN: ld.lld %t/a.o -T %t/eh-frame-non-zero-offset.t -o %t/non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld %t/a.o -T %t/eh-frame-zero-offset.t -o %t/zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO: {{[0-9]+}}: 00000080 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 000000ac {{.*}} __eh_frame_end
+
+// NONZERO: 0x00000074 00000000 00000000 00000000 10000000
+// NONZERO-NEXT: 0x00000084 00000000 017a5200 017c0e01 1b0c0d00
+// NONZERO-NEXT: 0x00000094 10000000 18000000 64ffffff 04000000
+// NONZERO-NEXT: 0x000000a4 00000000 00000000
+
+// ZERO: {{[0-9]+}}: 00000080 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 000000ac {{.*}} __eh_frame_end
+
+// ZERO: 0x00000080 10000000 00000000 017a5200 017c0e01
+// ZERO-NEXT: 0x00000090 1b0c0d00 10000000 18000000 64ffffff
+// ZERO-NEXT: 0x000000a0 04000000 00000000 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : {
+ /* Alignment padding within .eh_frame */
+ . = ALIGN(128);
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : ALIGN(128) {
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- a.s
+.section .text.01, "ax",%progbits
+.global f1
+.type f1, %function
+f1:
+.cfi_startproc
+.cfi_sections .eh_frame
+.space 4
+.cfi_endproc
diff --git a/lld/test/ELF/eh-frame-nonzero-offset-ppc.s b/lld/test/ELF/eh-frame-nonzero-offset-ppc.s
new file mode 100644
index 000000000000000..2b736ab383ffeca
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-ppc.s
@@ -0,0 +1,54 @@
+// REQUIRES: ppc
+// RUN: rm -rf %t && split-file %s %t
+
+// RUN: llvm-mc -filetype=obj -triple=ppc64le %t/a.s -o %t/a.o
+// RUN: ld.lld %t/a.o -T %t/eh-frame-non-zero-offset.t -o %t/non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld %t/a.o -T %t/eh-frame-zero-offset.t -o %t/zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO: {{[0-9]+}}: 0000000000000080 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 00000000000000ac {{.*}} __eh_frame_end
+
+// NONZERO: 0x00000078 00000000 00000000 10000000 00000000
+// NONZERO-NEXT: 0x00000088 017a5200 04784101 1b0c0100 10000000
+// NONZERO-NEXT: 0x00000098 18000000 64ffffff 04000000 00000000
+// NONZERO-NEXT: 0x000000a8 00000000
+
+// ZERO: {{[0-9]+}}: 0000000000000080 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 00000000000000ac {{.*}} __eh_frame_end
+
+// ZERO: 0x00000080 10000000 00000000 017a5200 04784101
+// ZERO-NEXT: 0x00000090 1b0c0100 10000000 18000000 64ffffff
+// ZERO-NEXT: 0x000000a0 04000000 00000000 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : {
+ /* Alignment padding within .eh_frame */
+ . = ALIGN(128);
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : ALIGN(128) {
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- a.s
+.section .text.01, "ax",%progbits
+.global f1
+.type f1, %function
+f1:
+.cfi_startproc
+.space 4
+.cfi_endproc
diff --git a/lld/test/ELF/eh-frame-nonzero-offset-x86.s b/lld/test/ELF/eh-frame-nonzero-offset-x86.s
new file mode 100644
index 000000000000000..d5537346c338e08
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-x86.s
@@ -0,0 +1,54 @@
+// REQUIRES: x86
+// RUN: rm -rf %t && split-file %s %t
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o
+// RUN: ld.lld %t/a.o -T %t/eh-frame-non-zero-offset.t -o %t/non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld %t/a.o -T %t/eh-frame-zero-offset.t -o %t/zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame %t/zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO: {{[0-9]+}}: 0000000000000080 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 00000000000000b4 {{.*}} __eh_frame_end
+
+// NONZERO: 0x00000078 00000000 00000000 14000000 00000000
+// NONZERO-NEXT: 0x00000088 017a5200 01781001 1b0c0708 90010000
+// NONZERO-NEXT: 0x00000098 14000000 1c000000 60ffffff 04000000
+// NONZERO-NEXT: 0x000000a8 00000000 00000000 00000000
+
+// ZERO: {{[0-9]+}}: 0000000000000080 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 00000000000000b4 {{.*}} __eh_frame_end
+
+// ZERO: 0x00000080 14000000 00000000 017a5200 01781001
+// ZERO-NEXT: 0x00000090 1b0c0708 90010000 14000000 1c000000
+// ZERO-NEXT: 0x000000a0 60ffffff 04000000 00000000 00000000
+// ZERO-NEXT: 0x000000b0 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : {
+ /* Alignment padding within .eh_frame */
+ . = ALIGN(128);
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+ .text : { *(.text .text.*) }
+ .eh_frame : ALIGN(128) {
+ __eh_frame_start = .;
+ *(.eh_frame .eh_frame.*) ;
+ __eh_frame_end = .;
+ }
+}
+
+//--- a.s
+.section .text
+.globl f1
+f1:
+.cfi_startproc
+.space 4
+.cfi_endproc
>From a6e2b6c89af6c2a9fd813686e2a48a19111851ae Mon Sep 17 00:00:00 2001
From: Simi Pallipurath <simi.pallipurath at arm.com>
Date: Sat, 30 Sep 2023 17:13:21 +0100
Subject: [PATCH 3/3] fixup! [LLD]lld incorrectly handles .eh_frame when it has
a non-zero offset within its output section.
Adding outSecOff in eh_frame_hdr section as
finalizeAddressDependentContent() may have altered
the corresponding outSecOff. This is required to get
the correct initial location of each FDE entries.
---
lld/ELF/SyntheticSections.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 416ebdc266eaa82..0f7ebf9d7ba840b 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -587,14 +587,10 @@ uint64_t EhFrameSection::getFdePc(uint8_t *buf, size_t fdeOff,
// the .eh_frame section.
size_t off = fdeOff + 8;
uint64_t addr = readFdeAddr(buf + off, enc & 0xf);
- // Adding outSecOff as finalizeAddressDependentContent()
- // may have altered the corresponding outSecOff. This is
- // required to get the correct PC relative offset.
- off = off + outSecOff;
if ((enc & 0x70) == DW_EH_PE_absptr)
return addr;
if ((enc & 0x70) == DW_EH_PE_pcrel)
- return addr + getParent()->addr + off;
+ return addr + getParent()->addr + off + outSecOff;
fatal("unknown FDE size relative encoding");
}
More information about the lldb-commits
mailing list