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

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 11 09:16:55 PDT 2023

@@ -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))
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 <stdio.h>

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
Caught int 55
clang++ -fuse-ld=lld throw.cpp -o throw.exe -Wl,--script=ld.script
[1]    444896 abort (core dumped)  ./throw.exe


More information about the llvm-commits mailing list