[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:
Maksim Panchenko
2024-11-18 20:42:38 -08:00
committed by GitHub
parent 1eaa17975d
commit 08ef939637
2 changed files with 63 additions and 29 deletions

View File

@@ -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.