[lld] [lld][ELF] Refresh .eh_frame_hdr cache after cfi jump table relaxation (PR #228218)

Martin Levesque via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 12:46:09 PDT 2026


https://github.com/wehzzz created https://github.com/llvm/llvm-project/pull/228218

relaxCFIJumpTables() can change section placement without changing the output size. Preserve that change in the fixed-point loop so at least one more address assignment is done, thus rebuilding the cached FDE entries in .eh_frame_hdr.

Fixes #226166

>From 70136109b3eb8fabd9d7ee3332e3c43b4aedf152 Mon Sep 17 00:00:00 2001
From: Martin Levesque <martin.levesque at datadoghq.com>
Date: Thu, 1 Oct 2026 19:33:31 +0000
Subject: [PATCH] [lld][ELF] Refresh .eh_frame_hdr cache after cfi jump table
 relaxation

relaxCFIJumpTables() can change section placement without changing the
output size. Preserve that change in the fixed-point loop so at least one
more address assignment is done, thus rebuilding the cached FDE
entries in .eh_frame_hdr.

Fixes #226166
---
 lld/ELF/Arch/X86_64.cpp                     |  7 +-
 lld/ELF/Target.h                            |  5 +-
 lld/ELF/Writer.cpp                          | 11 +--
 lld/test/ELF/eh-frame-hdr-cfi-jump-tables.s | 78 +++++++++++++++++++++
 4 files changed, 92 insertions(+), 9 deletions(-)
 create mode 100644 lld/test/ELF/eh-frame-hdr-cfi-jump-tables.s

diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index c1d1db1d0133c..596b3c47115a6 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -51,7 +51,7 @@ class X86_64 : public TargetInfo {
   bool deleteFallThruJmpInsn(InputSection &is,
                              InputSection *nextIS) const override;
   bool relaxOnce(int pass) const override;
-  void relaxCFIJumpTables() const override;
+  bool relaxCFIJumpTables() const override;
   void applyBranchToBranchOpt() const override;
   template <class ELFT, class RelTy>
   void scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
@@ -314,7 +314,7 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is,
   return true;
 }
 
-void X86_64::relaxCFIJumpTables() const {
+bool X86_64::relaxCFIJumpTables() const {
   // Relax CFI jump tables.
   // - Split jump table into pieces and place target functions inside the jump
   //   table if small enough.
@@ -480,7 +480,7 @@ void X86_64::relaxCFIJumpTables() const {
   }
 
   if (sectionReplacements.empty())
-    return;
+    return false;
 
   // Now that we have the complete mapping of replacements, go through the input
   // section lists and apply the replacements.
@@ -502,6 +502,7 @@ void X86_64::relaxCFIJumpTables() const {
       isd->sections = std::move(newSections);
     }
   }
+  return true;
 }
 
 bool X86_64::relaxOnce(int pass) const {
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 174e389db155d..ef9c2eb1f484a 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -115,8 +115,9 @@ class TargetInfo {
 
   // Do a linker relaxation pass and return true if we changed something.
   virtual bool relaxOnce(int pass) const { return false; }
-  // Relax CFI jump tables if implemented by target.
-  virtual void relaxCFIJumpTables() const {}
+  // Relax CFI jump tables if implemented by target and return true if we
+  // changed something.
+  virtual bool relaxCFIJumpTables() const { return false; }
   virtual bool synthesizeAlign(uint64_t &dot, InputSection *sec) {
     return false;
   }
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 4fac47b548936..eaddc96804e0d 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1520,16 +1520,19 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
   if (ctx.arg.randomizeSectionPadding)
     randomizeSectionPadding(ctx);
 
+  bool cfiJumpTablesChanged = false;
   if (ctx.arg.branchToBranch)
-    ctx.target->relaxCFIJumpTables();
+    cfiJumpTablesChanged = ctx.target->relaxCFIJumpTables();
 
   // Iterate until a fixed point is reached, skipping relocatable links since
   // the final addresses are unavailable.
   uint32_t pass = 0, assignPasses = 0;
   while (!ctx.arg.relocatable) {
-    bool changed = ctx.target->needsThunks
-                       ? tc.createThunks(pass, ctx.outputSections)
-                       : ctx.target->relaxOnce(pass);
+    bool changed = cfiJumpTablesChanged;
+    cfiJumpTablesChanged = false;
+    changed |= ctx.target->needsThunks
+                   ? tc.createThunks(pass, ctx.outputSections)
+                   : ctx.target->relaxOnce(pass);
     bool spilled = ctx.script->spillSections();
     changed |= spilled;
     ++pass;
diff --git a/lld/test/ELF/eh-frame-hdr-cfi-jump-tables.s b/lld/test/ELF/eh-frame-hdr-cfi-jump-tables.s
new file mode 100644
index 0000000000000..9bbeddd4690aa
--- /dev/null
+++ b/lld/test/ELF/eh-frame-hdr-cfi-jump-tables.s
@@ -0,0 +1,78 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld --eh-frame-hdr -O2 --no-branch-to-branch %t.o -shared -o %t2
+# RUN: llvm-readelf --unwind %t2 | FileCheck %s
+# RUN: ld.lld --eh-frame-hdr -O2 %t.o -shared -o %t
+# RUN: llvm-readelf --unwind %t | FileCheck %s
+
+# CHECK:      fde_count: 1
+# CHECK:      entry 0 {
+# CHECK-NEXT:   initial_location: [[PC:0x[0-9a-f]+]]
+# CHECK-NEXT:   address: [[FDE:0x[0-9a-f]+]]
+# CHECK:      [{{ *}}[[FDE]]{{ *}}] FDE
+# CHECK-NEXT:   initial_location: [[PC]]
+
+.section .text.jt,"ax", at llvm_cfi_jump_table,8
+.type f1, at function
+f1:
+  jmp f1.cfi
+  .balign 8, 0xcc
+.type f2, at function
+f2:
+  jmp f2.cfi
+  .balign 8, 0xcc
+.type f3, at function
+f3:
+  jmp f3.cfi
+  .balign 8, 0xcc
+.type f4, at function
+f4:
+  jmp f4.cfi
+  .balign 8, 0xcc
+
+.section .text.f1,"ax", at progbits
+f1.cfi:
+  ret
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+
+.section .text.f2,"ax", at progbits
+f2.cfi:
+  ret
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+
+.section .text.f3,"ax", at progbits
+f3.cfi:
+  ret
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+  nop
+
+.section .text.f4,"ax", at progbits
+.type f4.cfi, at function
+f4.cfi:
+  .cfi_startproc
+  ret
+  .cfi_endproc
+.size f4.cfi, .-f4.cfi



More information about the llvm-commits mailing list