https://github.com/simpal01 updated https://github.com/llvm/llvm-project/pull/65966
>From 8b44aa203b97b8944f236701bfeb92f0b1e8f407 Mon Sep 17 00:00:00 2001 From: Simi Pallipurath <simi.pallipur...@arm.com> 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..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 2e3a0de9714856cb8fa992f1818e5de7053dd32b Mon Sep 17 00:00:00 2001 From: Simi Pallipurath <simi.pallipur...@arm.com> Date: Mon, 18 Sep 2023 19:50:56 +0100 Subject: [PATCH 2/2] 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits