[llvm] [BOLT] Overwrite .eh_frame_hdr in-place (PR #116730)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 18 17:55:01 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-bolt
Author: Maksim Panchenko (maksfb)
<details>
<summary>Changes</summary>
If the new EH frame header can fit into the original .eh_frame_hdr section, overwrite it in-place and pad with zeroes.
---
Full diff: https://github.com/llvm/llvm-project/pull/116730.diff
2 Files Affected:
- (modified) bolt/lib/Rewrite/RewriteInstance.cpp (+51-29)
- (added) bolt/test/eh-frame-hdr.test (+12)
``````````diff
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 1fcf2bb959bbbb..40769944e3876b 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -5791,42 +5791,64 @@ void RewriteInstance::writeEHFrameHeader() {
LLVM_DEBUG(dbgs() << "BOLT: writing a new " << getEHFrameHdrSectionName()
<< '\n');
- NextAvailableAddress =
- appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
+ // Try to overwrite the original .eh_frame_hdr if the size permits.
+ uint64_t EHFrameHdrOutputAddress = 0;
+ uint64_t EHFrameHdrFileOffset = 0;
+ std::vector<char> NewEHFrameHdr;
+ BinarySection *OldEHFrameHdrSection = getSection(getEHFrameHdrSectionName());
+ if (OldEHFrameHdrSection) {
+ NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
+ RelocatedEHFrame, NewEHFrame, OldEHFrameHdrSection->getAddress());
+ if (NewEHFrameHdr.size() <= OldEHFrameHdrSection->getSize()) {
+ BC->outs() << "BOLT-INFO: rewriting " << getEHFrameHdrSectionName()
+ << " in-place\n";
+ EHFrameHdrOutputAddress = OldEHFrameHdrSection->getAddress();
+ EHFrameHdrFileOffset = OldEHFrameHdrSection->getInputFileOffset();
+ } else {
+ OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() +
+ getEHFrameHdrSectionName());
+ OldEHFrameHdrSection = nullptr;
+ }
+ }
- const uint64_t EHFrameHdrOutputAddress = NextAvailableAddress;
- const uint64_t EHFrameHdrFileOffset =
- getFileOffsetForAddress(NextAvailableAddress);
+ // If there was not enough space, allocate more memory for .eh_frame_hdr.
+ if (!OldEHFrameHdrSection) {
+ NextAvailableAddress =
+ appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
- std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
- RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress);
+ EHFrameHdrOutputAddress = NextAvailableAddress;
+ EHFrameHdrFileOffset = getFileOffsetForAddress(NextAvailableAddress);
+
+ NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
+ RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress);
+
+ NextAvailableAddress += NewEHFrameHdr.size();
+ if (!BC->BOLTReserved.empty() &&
+ (NextAvailableAddress > BC->BOLTReserved.end())) {
+ BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
+ << " into reserved space\n";
+ exit(1);
+ }
+
+ // Create a new entry in the section header table.
+ const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
+ /*IsText=*/false,
+ /*IsAllocatable=*/true);
+ BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection(
+ getNewSecPrefix() + getEHFrameHdrSectionName(), ELF::SHT_PROGBITS,
+ Flags, nullptr, NewEHFrameHdr.size(), /*Alignment=*/1);
+ EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset);
+ EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress);
+ EHFrameHdrSec.setOutputName(getEHFrameHdrSectionName());
+ }
Out->os().seek(EHFrameHdrFileOffset);
Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size());
- const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
- /*IsText=*/false,
- /*IsAllocatable=*/true);
- BinarySection *OldEHFrameHdrSection = getSection(getEHFrameHdrSectionName());
+ // Pad the contents if overwriting in-place.
if (OldEHFrameHdrSection)
- OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() +
- getEHFrameHdrSectionName());
-
- BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection(
- getNewSecPrefix() + getEHFrameHdrSectionName(), ELF::SHT_PROGBITS, Flags,
- nullptr, NewEHFrameHdr.size(), /*Alignment=*/1);
- EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset);
- EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress);
- EHFrameHdrSec.setOutputName(getEHFrameHdrSectionName());
-
- NextAvailableAddress += EHFrameHdrSec.getOutputSize();
-
- if (!BC->BOLTReserved.empty() &&
- (NextAvailableAddress > BC->BOLTReserved.end())) {
- BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
- << " into reserved space\n";
- exit(1);
- }
+ Out->os().write_zeros(OldEHFrameHdrSection->getSize() -
+ NewEHFrameHdr.size());
// Merge new .eh_frame with the relocated original so that gdb can locate all
// FDEs.
diff --git a/bolt/test/eh-frame-hdr.test b/bolt/test/eh-frame-hdr.test
new file mode 100644
index 00000000000000..4d718c850e2f28
--- /dev/null
+++ b/bolt/test/eh-frame-hdr.test
@@ -0,0 +1,12 @@
+# Check that llvm-bolt overwrites .eh_frame_hdr in-place.
+
+REQUIRES: system-linux
+
+RUN: %clang %cflags %p/Inputs/hello.c -o %t -Wl,-q
+RUN: llvm-bolt %t -o %t.bolt --use-old-text \
+RUN: | FileCheck %s --check-prefix=CHECK-BOLT
+RUN: llvm-readelf -WS %t.bolt | FileCheck %s
+
+CHECK-BOLT: rewriting .eh_frame_hdr in-place
+
+CHECK-NOT: .bolt.org.eh_frame_hdr
``````````
</details>
https://github.com/llvm/llvm-project/pull/116730
More information about the llvm-commits
mailing list