[lld] [LLD][AARCH64] lld incorrectly handles .eh_frame when it has a non-zero offset within its output section. (PR #65966)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 11 08:05:22 PDT 2023


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 <simi.pallipurath at 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..fd0ef28737042b4 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -1081,3 +1081,6 @@ void lld::elf::createTaggedSymbols(const SmallVector<ELFFileBase *, 0> &files) {
     symbol->setIsTagged(true);
   }
 }
+  else if (auto *eh = dyn_cast<EhInputSection>(&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 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 31e116847f013c2c9301bb1868fa7a10af9bdf8b 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 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<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];



More information about the llvm-commits mailing list