[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
https://github.com/simpal01 updated https://github.com/llvm/llvm-project/pull/65966: >From 7cd4fe122a329d29023f978991baa486266a32f3 Mon Sep 17 00:00:00 2001 From: Simi Pallipurath Date: Mon, 11 Sep 2023 14:42:27 +0100 Subject: [PATCH 1/2] [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..fd0ef28737042b4 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -1081,3 +1081,6 @@ void lld::elf::createTaggedSymbols(const SmallVector &files) { symbol->setIsTagged(true); } } + else if (auto *eh = dyn_cast(&sec)) +if (InputSection *isec = eh->getParent()) + secAddr += isec->outSecOff; 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 000..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]+}}: 0080 {{.*}} __eh_frame_start +// NONZERO-NEXT: {{[0-9]+}}: 00ac {{.*}} __eh_frame_end + +// NONZERO: 0x0078 1000 +// NONZERO-NEXT: 0x0088 017a5200 017c1e01 1b0c1f00 1000 +// NONZERO-NEXT: 0x0098 1800 64ff 0800 +// NONZERO-NEXT: 0x00a8 + +// ZERO: {{[0-9]+}}: 0080 {{.*}} __eh_frame_start +// ZERO-NEXT: {{[0-9]+}}: 00ac {{.*}} __eh_frame_end + +// ZERO: 0x0080 1000 017a5200 017c1e01 +// ZERO-NEXT: 0x0090 1b0c1f00 1000 1800 64ff +// ZERO-NEXT: 0x00a0 0800 + +//--- 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 31e116847f013c2c9301bb1868fa7a10af9bdf8b Mon Sep 17 00:00:00 2001 From: Simi Pallipurath Date: Mon, 11 Sep 2023 14:42:27 +0100 Subject: [PATCH 2/2] [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 +++ 1 file changed, 3 insertions(+) diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index fd0ef28737042b4..411c0a046bd7c58 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(&sec)) secAddr += s->outSecOff; + else if (auto *eh = dyn_cast(&sec)) +if (InputSection *isec = eh->getParent()) + secAddr += isec->outSecOff; AArch64Relaxer relaxer(sec.relocs()); for (size_t i = 0, size = sec.relocs().size(); i !=
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
https://github.com/simpal01 updated https://github.com/llvm/llvm-project/pull/65966: >From 7cd4fe122a329d29023f978991baa486266a32f3 Mon Sep 17 00:00:00 2001 From: Simi Pallipurath 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..fd0ef28737042b4 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -1081,3 +1081,6 @@ void lld::elf::createTaggedSymbols(const SmallVector &files) { symbol->setIsTagged(true); } } + else if (auto *eh = dyn_cast(&sec)) +if (InputSection *isec = eh->getParent()) + secAddr += isec->outSecOff; 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 000..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]+}}: 0080 {{.*}} __eh_frame_start +// NONZERO-NEXT: {{[0-9]+}}: 00ac {{.*}} __eh_frame_end + +// NONZERO: 0x0078 1000 +// NONZERO-NEXT: 0x0088 017a5200 017c1e01 1b0c1f00 1000 +// NONZERO-NEXT: 0x0098 1800 64ff 0800 +// NONZERO-NEXT: 0x00a8 + +// ZERO: {{[0-9]+}}: 0080 {{.*}} __eh_frame_start +// ZERO-NEXT: {{[0-9]+}}: 00ac {{.*}} __eh_frame_end + +// ZERO: 0x0080 1000 017a5200 017c1e01 +// ZERO-NEXT: 0x0090 1b0c1f00 1000 1800 64ff +// ZERO-NEXT: 0x00a0 0800 + +//--- 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 31e116847f013c2c9301bb1868fa7a10af9bdf8b Mon Sep 17 00:00:00 2001 From: Simi Pallipurath Date: Mon, 11 Sep 2023 14:42:27 +0100 Subject: [PATCH 2/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 +++ 1 file changed, 3 insertions(+) diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index fd0ef28737042b4..411c0a046bd7c58 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(&sec)) secAddr += s->outSecOff; + else if (auto *eh = dyn_cast(&sec)) +if (InputSection *isec = eh->getParent()) + secAddr += isec->outSecOff; AArch64Relaxer relaxer(sec.relocs()); for (size_t i = 0, size = sec.relocs().size(); i !=
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
https://github.com/simpal01 ready_for_review https://github.com/llvm/llvm-project/pull/65966 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
https://github.com/smithp35 edited https://github.com/llvm/llvm-project/pull/65966 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
https://github.com/smithp35 commented: This will only fix the problem for AArch64, but it also affects other targets. Assuming relocateAlloc is the best place to fix this, then it would need applying in all instances of relocateAlloc. https://github.com/llvm/llvm-project/pull/65966 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
@@ -770,6 +770,9 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { uint64_t secAddr = sec.getOutputSection()->addr; if (auto *s = dyn_cast(&sec)) secAddr += s->outSecOff; + else if (auto *eh = dyn_cast(&sec)) smithp35 wrote: I don't think this problem specific to AArch64? It would also affect the other targets that use .eh_frame such as x86_64. As I understand it this was triggered by the Picolibc linker script (https://github.com/picolibc/picolibc/blob/main/picolibc.ld.in) with extract: ``` .except_ordered : { *(.gcc_except_table *.gcc_except_table.*) KEEP (*(.eh_frame .eh_frame.*)) *(.ARM.extab* .gnu.linkonce.armextab.*) } >flash AT>flash :text ``` Which has the .eh_frame sections after .gcc_except_table. I made a failing test case for x86_64 by editing the output of GNU ld's --verbose and adding a dummy QUAD statement. I've not included the whole ld --verbose output as it is rather long. ``` /* Insert QUAD(0) to make .eh_frame start at non 0 offset within ouptut section */ .eh_frame : ONLY_IF_RO { QUAD(0); KEEP (*(.eh_frame)) *(.eh_frame.*) } ``` With the simple test program ``` #include int main(void) { try { throw 55; } catch (int i) { printf("Caught int %d\n", i); } catch (...) { printf("Caught generic\n"); } return 0; } ``` With results: ``` clang++ -fuse-ld=bfd throw.cpp -o throw.exe -Wl,--script=ld.script ./throw.exe Caught int 55 clang++ -fuse-ld=lld throw.cpp -o throw.exe -Wl,--script=ld.script ./throw.exe [1]444896 abort (core dumped) ./throw.exe ``` https://github.com/llvm/llvm-project/pull/65966 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
@@ -770,6 +770,9 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { uint64_t secAddr = sec.getOutputSection()->addr; if (auto *s = dyn_cast(&sec)) secAddr += s->outSecOff; + else if (auto *eh = dyn_cast(&sec)) simpal01 wrote: yeah this affects all other targets (might be X86 and PPC as well). https://github.com/llvm/llvm-project/pull/65966 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
@@ -770,6 +770,9 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { uint64_t secAddr = sec.getOutputSection()->addr; if (auto *s = dyn_cast(&sec)) secAddr += s->outSecOff; + else if (auto *eh = dyn_cast(&sec)) simpal01 wrote: i could not find the general way of fixing this without modifying target->relocateAlloc. https://github.com/llvm/llvm-project/pull/65966 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)
https://github.com/simpal01 updated https://github.com/llvm/llvm-project/pull/65966 >From eb4d99345cbe9aba6b909ccbc7ce932dcaef3f7d Mon Sep 17 00:00:00 2001 From: Simi Pallipurath Date: Mon, 11 Sep 2023 14:42:27 +0100 Subject: [PATCH] [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(&sec)) secAddr += s->outSecOff; + else if (auto *eh = dyn_cast(&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 000..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]+}}: 0080 {{.*}} __eh_frame_start +// NONZERO-NEXT: {{[0-9]+}}: 00ac {{.*}} __eh_frame_end + +// NONZERO: 0x0078 1000 +// NONZERO-NEXT: 0x0088 017a5200 017c1e01 1b0c1f00 1000 +// NONZERO-NEXT: 0x0098 1800 64ff 0800 +// NONZERO-NEXT: 0x00a8 + +// ZERO: {{[0-9]+}}: 0080 {{.*}} __eh_frame_start +// ZERO-NEXT: {{[0-9]+}}: 00ac {{.*}} __eh_frame_end + +// ZERO: 0x0080 1000 017a5200 017c1e01 +// ZERO-NEXT: 0x0090 1b0c1f00 1000 1800 64ff +// ZERO-NEXT: 0x00a0 0800 + +//--- 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 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits