[lld] 3cde1d8 - [ELF] Handle relocations in synthetic .eh_frame with a non-zero offset within the output section (#65966)

via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 3 02:20:19 PDT 2023


Author: simpal01
Date: 2023-10-03T10:20:14+01:00
New Revision: 3cde1d8000e177409b220cea0d1f7250ab1b75d6

URL: https://github.com/llvm/llvm-project/commit/3cde1d8000e177409b220cea0d1f7250ab1b75d6
DIFF: https://github.com/llvm/llvm-project/commit/3cde1d8000e177409b220cea0d1f7250ab1b75d6.diff

LOG: [ELF] Handle relocations in synthetic .eh_frame with a non-zero offset within the output section (#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.

Added: 
    lld/test/ELF/eh-frame-nonzero-offset-aarch64.s
    lld/test/ELF/eh-frame-nonzero-offset-arm.s
    lld/test/ELF/eh-frame-nonzero-offset-ppc.s
    lld/test/ELF/eh-frame-nonzero-offset-x86.s

Modified: 
    lld/ELF/Arch/AArch64.cpp
    lld/ELF/Arch/PPC64.cpp
    lld/ELF/Arch/X86_64.cpp
    lld/ELF/SyntheticSections.cpp
    lld/ELF/Target.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 174a0a3624f7765..048f0ec30ebd283 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -770,6 +770,8 @@ 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 *ehIn = dyn_cast<EhInputSection>(&sec))
+    secAddr += ehIn->getParent()->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..097a57514770aaf 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -1563,6 +1563,8 @@ 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))
+    secAddr += ehIn->getParent()->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..9e49f54f6389a6c 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -989,6 +989,8 @@ 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))
+    secAddr += ehIn->getParent()->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..0f7ebf9d7ba840b 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -583,13 +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);
   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");
 }
 

diff  --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 32bb2164a208b85..41990f40f68b82a 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -159,6 +159,8 @@ 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))
+    secAddr += ehIn->getParent()->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-aarch64.s b/lld/test/ELF/eh-frame-nonzero-offset-aarch64.s
new file mode 100644
index 000000000000000..31e63a9c140985c
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-aarch64.s
@@ -0,0 +1,53 @@
+// REQUIRES: aarch64
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64 a.s -o a.o
+// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO:      {{[0-9]+}}: 0000000000000088 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 00000000000000b4 {{.*}} __eh_frame_end
+
+// NONZERO:      0x00000088 10000000 00000000 017a5200 017c1e01
+// NONZERO-NEXT: 0x00000098 1b0c1f00 10000000 18000000 5cffffff
+// NONZERO-NEXT: 0x000000a8 04000000 00000000 00000000
+
+// ZERO:      {{[0-9]+}}: 0000000000000008 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 0000000000000034 {{.*}} __eh_frame_end
+
+// ZERO:      0x00000008 10000000 00000000 017a5200 017c1e01
+// ZERO-NEXT: 0x00000018 1b0c1f00 10000000 18000000 dcffffff
+// ZERO-NEXT: 0x00000028 04000000 00000000 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    /* Padding within .eh_frame */
+    . += 128;
+    __eh_frame_start = .;
+    *(.eh_frame) ;
+    __eh_frame_end = .;
+  }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    __eh_frame_start = .;
+    *(.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-arm.s b/lld/test/ELF/eh-frame-nonzero-offset-arm.s
new file mode 100644
index 000000000000000..eec3943a5554c81
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-arm.s
@@ -0,0 +1,54 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -filetype=obj -triple=arm a.s -o a.o
+// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO:      {{[0-9]+}}: 00000084 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 000000b0 {{.*}} __eh_frame_end
+
+// NONZERO:      0x00000084 10000000 00000000 017a5200 017c0e01
+// NONZERO-NEXT: 0x00000094 1b0c0d00 10000000 18000000 60ffffff
+// NONZERO-NEXT: 0x000000a4 04000000 00000000 00000000
+
+// ZERO:      {{[0-9]+}}: 00000004 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 00000030 {{.*}} __eh_frame_end
+
+// ZERO:      0x00000004 10000000 00000000 017a5200 017c0e01
+// ZERO-NEXT: 0x00000014 1b0c0d00 10000000 18000000 e0ffffff
+// ZERO-NEXT: 0x00000024 04000000 00000000 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    /* Padding within .eh_frame */
+    . += 128;
+    __eh_frame_start = .;
+    *(.eh_frame) ;
+    __eh_frame_end = .;
+  }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    __eh_frame_start = .;
+    *(.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..7b147cf34715a25
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-ppc.s
@@ -0,0 +1,53 @@
+// REQUIRES: ppc
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -filetype=obj -triple=ppc64le a.s -o a.o
+// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO:      {{[0-9]+}}: 0000000000000088 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 00000000000000b4 {{.*}} __eh_frame_end
+
+// NONZERO:      0x00000088 10000000 00000000 017a5200 04784101
+// NONZERO-NEXT: 0x00000098 1b0c0100 10000000 18000000 5cffffff
+// NONZERO-NEXT: 0x000000a8 04000000 00000000 00000000
+
+// ZERO:      {{[0-9]+}}: 0000000000000008 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 0000000000000034 {{.*}} __eh_frame_end
+
+// ZERO:      0x00000008 10000000 00000000 017a5200 04784101
+// ZERO-NEXT: 0x00000018 1b0c0100 10000000 18000000 dcffffff
+// ZERO-NEXT: 0x00000028 04000000 00000000 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    /* Padding within .eh_frame */
+    . += 128;
+    __eh_frame_start = .;
+    *(.eh_frame) ;
+    __eh_frame_end = .;
+  }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    __eh_frame_start = .;
+    *(.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..e433d45a839397b
--- /dev/null
+++ b/lld/test/ELF/eh-frame-nonzero-offset-x86.s
@@ -0,0 +1,55 @@
+// REQUIRES: x86
+// RUN: rm -rf %t && split-file %s %t && cd %t
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+// RUN: ld.lld a.o -T eh-frame-non-zero-offset.t -o non-zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame non-zero | FileCheck --check-prefix=NONZERO %s
+// RUN: ld.lld a.o -T eh-frame-zero-offset.t -o zero
+// RUN: llvm-readelf --program-headers --unwind --symbols -x .eh_frame zero | FileCheck --check-prefix=ZERO %s
+
+// NONZERO:      {{[0-9]+}}: 0000000000000088 {{.*}} __eh_frame_start
+// NONZERO-NEXT: {{[0-9]+}}: 00000000000000bc {{.*}} __eh_frame_end
+
+// NONZERO:      0x00000088 14000000 00000000 017a5200 01781001
+// NONZERO-NEXT: 0x00000098 1b0c0708 90010000 14000000 1c000000
+// NONZERO-NEXT: 0x000000a8 58ffffff 04000000 00000000 00000000
+// NONZERO-NEXT: 0x000000b8 00000000
+
+// ZERO:      {{[0-9]+}}: 0000000000000008 {{.*}} __eh_frame_start
+// ZERO-NEXT: {{[0-9]+}}: 000000000000003c {{.*}} __eh_frame_end
+
+// ZERO:      0x00000008 14000000 00000000 017a5200 01781001
+// ZERO-NEXT: 0x00000018 1b0c0708 90010000 14000000 1c000000
+// ZERO-NEXT: 0x00000028 d8ffffff 04000000 00000000 00000000
+// ZERO-NEXT: 0x00000038 00000000
+
+//--- eh-frame-non-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    /* Padding within .eh_frame */
+    . += 128;
+    __eh_frame_start = .;
+    *(.eh_frame) ;
+    __eh_frame_end = .;
+  }
+}
+
+//--- eh-frame-zero-offset.t
+SECTIONS {
+  .text : { *(.text .text.*) }
+  .eh_frame : {
+    __eh_frame_start = .;
+    *(.eh_frame) ;
+    __eh_frame_end = .;
+  }
+}
+
+//--- a.s
+.section .text.01, "ax",%progbits
+.global f1
+.type f1, %function
+f1:
+.cfi_startproc
+.space 4
+.cfi_endproc


        


More information about the llvm-commits mailing list