[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