Skip to content

Commit 08ef939

Browse files
authored
[BOLT] Overwrite .eh_frame_hdr in-place (#116730)
If the new EH frame header can fit into the original .eh_frame_hdr section, overwrite it in-place and pad with zeroes.
1 parent 1eaa179 commit 08ef939

File tree

2 files changed

+63
-29
lines changed

2 files changed

+63
-29
lines changed

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5791,42 +5791,64 @@ void RewriteInstance::writeEHFrameHeader() {
57915791
LLVM_DEBUG(dbgs() << "BOLT: writing a new " << getEHFrameHdrSectionName()
57925792
<< '\n');
57935793

5794-
NextAvailableAddress =
5795-
appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
5794+
// Try to overwrite the original .eh_frame_hdr if the size permits.
5795+
uint64_t EHFrameHdrOutputAddress = 0;
5796+
uint64_t EHFrameHdrFileOffset = 0;
5797+
std::vector<char> NewEHFrameHdr;
5798+
BinarySection *OldEHFrameHdrSection = getSection(getEHFrameHdrSectionName());
5799+
if (OldEHFrameHdrSection) {
5800+
NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
5801+
RelocatedEHFrame, NewEHFrame, OldEHFrameHdrSection->getAddress());
5802+
if (NewEHFrameHdr.size() <= OldEHFrameHdrSection->getSize()) {
5803+
BC->outs() << "BOLT-INFO: rewriting " << getEHFrameHdrSectionName()
5804+
<< " in-place\n";
5805+
EHFrameHdrOutputAddress = OldEHFrameHdrSection->getAddress();
5806+
EHFrameHdrFileOffset = OldEHFrameHdrSection->getInputFileOffset();
5807+
} else {
5808+
OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() +
5809+
getEHFrameHdrSectionName());
5810+
OldEHFrameHdrSection = nullptr;
5811+
}
5812+
}
57965813

5797-
const uint64_t EHFrameHdrOutputAddress = NextAvailableAddress;
5798-
const uint64_t EHFrameHdrFileOffset =
5799-
getFileOffsetForAddress(NextAvailableAddress);
5814+
// If there was not enough space, allocate more memory for .eh_frame_hdr.
5815+
if (!OldEHFrameHdrSection) {
5816+
NextAvailableAddress =
5817+
appendPadding(Out->os(), NextAvailableAddress, EHFrameHdrAlign);
58005818

5801-
std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
5802-
RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress);
5819+
EHFrameHdrOutputAddress = NextAvailableAddress;
5820+
EHFrameHdrFileOffset = getFileOffsetForAddress(NextAvailableAddress);
5821+
5822+
NewEHFrameHdr = CFIRdWrt->generateEHFrameHeader(
5823+
RelocatedEHFrame, NewEHFrame, EHFrameHdrOutputAddress);
5824+
5825+
NextAvailableAddress += NewEHFrameHdr.size();
5826+
if (!BC->BOLTReserved.empty() &&
5827+
(NextAvailableAddress > BC->BOLTReserved.end())) {
5828+
BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
5829+
<< " into reserved space\n";
5830+
exit(1);
5831+
}
5832+
5833+
// Create a new entry in the section header table.
5834+
const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
5835+
/*IsText=*/false,
5836+
/*IsAllocatable=*/true);
5837+
BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection(
5838+
getNewSecPrefix() + getEHFrameHdrSectionName(), ELF::SHT_PROGBITS,
5839+
Flags, nullptr, NewEHFrameHdr.size(), /*Alignment=*/1);
5840+
EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset);
5841+
EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress);
5842+
EHFrameHdrSec.setOutputName(getEHFrameHdrSectionName());
5843+
}
58035844

58045845
Out->os().seek(EHFrameHdrFileOffset);
58055846
Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size());
58065847

5807-
const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true,
5808-
/*IsText=*/false,
5809-
/*IsAllocatable=*/true);
5810-
BinarySection *OldEHFrameHdrSection = getSection(getEHFrameHdrSectionName());
5848+
// Pad the contents if overwriting in-place.
58115849
if (OldEHFrameHdrSection)
5812-
OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() +
5813-
getEHFrameHdrSectionName());
5814-
5815-
BinarySection &EHFrameHdrSec = BC->registerOrUpdateSection(
5816-
getNewSecPrefix() + getEHFrameHdrSectionName(), ELF::SHT_PROGBITS, Flags,
5817-
nullptr, NewEHFrameHdr.size(), /*Alignment=*/1);
5818-
EHFrameHdrSec.setOutputFileOffset(EHFrameHdrFileOffset);
5819-
EHFrameHdrSec.setOutputAddress(EHFrameHdrOutputAddress);
5820-
EHFrameHdrSec.setOutputName(getEHFrameHdrSectionName());
5821-
5822-
NextAvailableAddress += EHFrameHdrSec.getOutputSize();
5823-
5824-
if (!BC->BOLTReserved.empty() &&
5825-
(NextAvailableAddress > BC->BOLTReserved.end())) {
5826-
BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName()
5827-
<< " into reserved space\n";
5828-
exit(1);
5829-
}
5850+
Out->os().write_zeros(OldEHFrameHdrSection->getSize() -
5851+
NewEHFrameHdr.size());
58305852

58315853
// Merge new .eh_frame with the relocated original so that gdb can locate all
58325854
// FDEs.

bolt/test/eh-frame-hdr.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Check that llvm-bolt overwrites .eh_frame_hdr in-place.
2+
3+
REQUIRES: system-linux
4+
5+
RUN: %clang %cflags %p/Inputs/hello.c -o %t -Wl,-q
6+
RUN: llvm-bolt %t -o %t.bolt --use-old-text \
7+
RUN: | FileCheck %s --check-prefix=CHECK-BOLT
8+
RUN: llvm-readelf -WS %t.bolt | FileCheck %s
9+
10+
CHECK-BOLT: rewriting .eh_frame_hdr in-place
11+
12+
CHECK-NOT: .bolt.org.eh_frame_hdr

0 commit comments

Comments
 (0)