[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.
This commit is contained in:
parent
1eaa17975d
commit
08ef939637
@ -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.
|
||||
|
12
bolt/test/eh-frame-hdr.test
Normal file
12
bolt/test/eh-frame-hdr.test
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user