[llvm] [BOLT] Update __EH_FRAME_BEGIN__ for regenerated .eh_frame (PR #219387)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 28 00:04:51 PDT 2026


https://github.com/WangJee updated https://github.com/llvm/llvm-project/pull/219387

>From 4e95919f8a9ae753b2528729653314a39813a9b7 Mon Sep 17 00:00:00 2001
From: "wangjue.wangjue" <wangjue.wangjue at alibaba-inc.com>
Date: Fri, 28 Aug 2026 14:50:36 +0900
Subject: [PATCH] [BOLT] Update __EH_FRAME_BEGIN__ for regenerated .eh_frame

Remember the GNU frame-registration anchor while discovering input symbols, before local-name uniquification. Once the regenerated .eh_frame is finalized and mapped, mark its BinaryData as moved to the new section start.

Teach generic ELF symbol-table updates to honor moved BinaryData independently of --reorder-data, and make fallback symbol resolution return moved output addresses. This updates both references and symbol values without an EH-specific writer special case.

Add a RISC-V regression that covers local-name uniquification and a nonzero input section offset.

Assisted-by: AI
---
 bolt/include/bolt/Rewrite/RewriteInstance.h |  6 +++
 bolt/lib/Rewrite/RewriteInstance.cpp        | 23 +++++---
 bolt/test/RISCV/eh-frame-begin.s            | 60 +++++++++++++++++++++
 3 files changed, 83 insertions(+), 6 deletions(-)
 create mode 100644 bolt/test/RISCV/eh-frame-begin.s

diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 8299cc392eade..43e830013419b 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -467,6 +467,9 @@ class RewriteInstance {
 
   /// Common section names.
   static StringRef getEHFrameSectionName() { return ".eh_frame"; }
+
+  /// GNU crtbegin symbol used as the .eh_frame registration anchor.
+  static StringRef getEHFrameBeginSymbolName() { return "__EH_FRAME_BEGIN__"; }
   static StringRef getEHFrameHdrSectionName() { return ".eh_frame_hdr"; }
   static StringRef getRelaDynSectionName() { return ".rela.dyn"; }
 
@@ -614,6 +617,9 @@ class RewriteInstance {
   /// Exception handling and stack unwinding information in this binary.
   ErrorOr<BinarySection &> EHFrameSection{std::errc::bad_address};
 
+  /// GNU crtbegin symbol used to register the regenerated .eh_frame.
+  BinaryData *EHFrameBegin{nullptr};
+
   /// Helper for accessing sections by name.
   BinarySection *getSection(const Twine &Name) {
     ErrorOr<BinarySection &> ErrOrSection = BC->getUniqueSectionByName(Name);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 4486efe926d01..a57d57cf37420 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1062,6 +1062,7 @@ void RewriteInstance::discoverFileObjects() {
       continue;
 
     FileSymRefs.emplace(SymbolAddress, Symbol);
+    const bool IsEHFrameBegin = SymName == getEHFrameBeginSymbolName();
 
     // Skip symbols in PLT sections that will be registered by disassemblePLT().
     // ST_Debug covers section markers (lld/GNU ld), ST_Function covers
@@ -1178,6 +1179,12 @@ void RewriteInstance::discoverFileObjects() {
       LLVM_DEBUG(dbgs() << "BOLT-DEBUG: rejecting as symbol is not in code or "
                            "is in nobits section\n");
       registerName(SymbolSize);
+      if (IsEHFrameBegin &&
+          cantFail(Section->getName()) == getEHFrameSectionName()) {
+        EHFrameBegin = BC->getBinaryDataAtAddress(SymbolAddress);
+        assert(EHFrameBegin &&
+               "__EH_FRAME_BEGIN__ should have registered BinaryData");
+      }
       continue;
     }
 
@@ -4352,9 +4359,9 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {
   // If no new .eh_frame was written, remove relocated original .eh_frame.
   BinarySection *RelocatedEHFrameSection =
       getSection(".relocated" + getEHFrameSectionName());
+  BinarySection *NewEHFrameSection =
+      getSection(getNewSecPrefix() + getEHFrameSectionName());
   if (RelocatedEHFrameSection && RelocatedEHFrameSection->hasValidSectionID()) {
-    BinarySection *NewEHFrameSection =
-        getSection(getNewSecPrefix() + getEHFrameSectionName());
     if (!NewEHFrameSection || !NewEHFrameSection->isFinalized()) {
       // JITLink will still have to process relocations for the section, hence
       // we need to assign it the address that wouldn't result in relocation
@@ -4369,6 +4376,11 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {
   // Map the rest of the sections.
   mapAllocatableSections(MapSection);
 
+  // Make the GNU frame-registration anchor follow the regenerated .eh_frame.
+  // Record the move after mapping so the output address is available.
+  if (EHFrameBegin && NewEHFrameSection && NewEHFrameSection->isFinalized())
+    EHFrameBegin->setOutputLocation(*NewEHFrameSection, 0);
+
   if (!BC->BOLTReserved.empty()) {
     const uint64_t AllocatedSize =
         NextAvailableAddress - BC->BOLTReserved.start();
@@ -5855,9 +5867,7 @@ void RewriteInstance::updateELFSymbolTable(
             Function->getCodeSection(FF->getFragmentNum())->getIndex();
       } else {
         // Check if the symbol belongs to moved data object and update it.
-        BinaryData *BD = opts::ReorderData.empty()
-                             ? nullptr
-                             : BC->getBinaryDataAtAddress(Symbol.st_value);
+        BinaryData *BD = BC->getBinaryDataAtAddress(Symbol.st_value);
         if (BD && BD->isMoved() && !BD->isJumpTable()) {
           assert((!BD->getSize() || !Symbol.st_size ||
                   Symbol.st_size == BD->getSize()) &&
@@ -6972,7 +6982,8 @@ uint64_t RewriteInstance::getNewValueForSymbol(const StringRef Name) {
   if (!BD)
     return 0;
 
-  return BD->getAddress();
+  return BD->isMoved() && !BD->isJumpTable() ? BD->getOutputAddress()
+                                             : BD->getAddress();
 }
 
 uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const {
diff --git a/bolt/test/RISCV/eh-frame-begin.s b/bolt/test/RISCV/eh-frame-begin.s
new file mode 100644
index 0000000000000..2f06b46c2c40f
--- /dev/null
+++ b/bolt/test/RISCV/eh-frame-begin.s
@@ -0,0 +1,60 @@
+# REQUIRES: system-linux
+
+# Check that references and the symbol table entry for __EH_FRAME_BEGIN__ are
+# updated to the regenerated .eh_frame section.
+
+# RUN: llvm-mc -filetype=obj -triple riscv64-unknown-linux %s -o %t.o
+# RUN: ld.lld -q %t.o -o %t.exe
+# RUN: llvm-readelf -SW -s %t.exe | FileCheck %s --check-prefix=INPUT
+# RUN: llvm-bolt %t.exe -o %t.bolt.exe
+# RUN: llvm-readelf -SW -s %t.bolt.exe > %t.out
+# RUN: llvm-objdump -d --no-show-raw-insn %t.bolt.exe >> %t.out
+# RUN: FileCheck %s < %t.out
+
+  .section .eh_frame,"a", at progbits
+  # Keep a distinct CIE/FDE before the registration anchor so that the input
+  # symbol has a nonzero section offset.
+  .long 0x10
+  .long 0
+  .byte 0x01, 0x7a, 0x52, 0x00
+  # Use a non-default code alignment to prevent CIE merging.
+  .byte 0x02, 0x78, 0x01, 0x01
+  .byte 0x1b, 0x0c, 0x02, 0x00
+  .long 0x14
+  .long 0x18
+.Ldummy_fde_pc:
+  .long 0
+  .reloc .Ldummy_fde_pc, R_RISCV_32_PCREL, dummy
+  .dword 4
+  .long 0
+
+  # This symbol is local in GNU crtbegin and is uniquified internally by BOLT.
+  .type __EH_FRAME_BEGIN__, at object
+__EH_FRAME_BEGIN__:
+
+  .text
+  .type dummy, at function
+dummy:
+  ret
+  .size dummy, .-dummy
+
+  .globl _start
+  .type _start, at function
+_start:
+  .cfi_startproc
+.Lpcrel_hi:
+  auipc a0, %pcrel_hi(__EH_FRAME_BEGIN__)
+  addi a0, a0, %pcrel_lo(.Lpcrel_hi)
+  ret
+  .reloc 0, R_RISCV_NONE
+  .cfi_endproc
+  .size _start, .-_start
+
+# INPUT: ] .eh_frame PROGBITS [[#%x, INPUT_EH_FRAME_ADDR:]]
+# INPUT: [[#INPUT_EH_FRAME_ADDR + 0x2c]] 0 OBJECT LOCAL DEFAULT {{[0-9]+}} __EH_FRAME_BEGIN__
+
+# CHECK: ] .eh_frame PROGBITS [[#%x, EH_FRAME_ADDR:]]
+# CHECK: [[#EH_FRAME_ADDR]] 0 OBJECT LOCAL DEFAULT {{[0-9]+}} __EH_FRAME_BEGIN__
+# CHECK: [[#%x, START_ADDR:]] <_start>:
+# CHECK-NEXT: [[#START_ADDR]]: auipc a0, 0x0
+# CHECK-NEXT: [[#START_ADDR + 4]]: addi a0, a0, 0x[[#EH_FRAME_ADDR - START_ADDR]]



More information about the llvm-commits mailing list