[BOLT] Overwrite .eh_frame and .gcc_except_table (#116755)
Under --use-old-text or --strict, we completely rewrite contents of EH frames and exception tables sections. If new contents of either section do not exceed the size of the original section, rewrite the section in-place.
This commit is contained in:
parent
565a9ac7df
commit
996553228f
@ -87,6 +87,7 @@ class BinarySection {
|
||||
// been renamed)
|
||||
uint64_t OutputAddress{0}; // Section address for the rewritten binary.
|
||||
uint64_t OutputSize{0}; // Section size in the rewritten binary.
|
||||
// Can exceed OutputContents with padding.
|
||||
uint64_t OutputFileOffset{0}; // File offset in the rewritten binary file.
|
||||
StringRef OutputContents; // Rewritten section contents.
|
||||
const uint64_t SectionNumber; // Order in which the section was created.
|
||||
@ -474,6 +475,11 @@ public:
|
||||
/// Use name \p SectionName for the section during the emission.
|
||||
void emitAsData(MCStreamer &Streamer, const Twine &SectionName) const;
|
||||
|
||||
/// Write finalized contents of the section. If OutputSize exceeds the size of
|
||||
/// the OutputContents, append zero padding to the stream and return the
|
||||
/// number of byte written which should match the OutputSize.
|
||||
uint64_t write(raw_ostream &OS) const;
|
||||
|
||||
using SymbolResolverFuncTy = llvm::function_ref<uint64_t(const MCSymbol *)>;
|
||||
|
||||
/// Flush all pending relocations to patch original contents of sections
|
||||
@ -497,6 +503,9 @@ public:
|
||||
IsFinalized = true;
|
||||
}
|
||||
|
||||
/// When writing section contents, add \p PaddingSize zero bytes at the end.
|
||||
void addPadding(uint64_t PaddingSize) { OutputSize += PaddingSize; }
|
||||
|
||||
/// Reorder the contents of this section according to /p Order. If
|
||||
/// /p Inplace is true, the entire contents of the section is reordered,
|
||||
/// otherwise the new contents contain only the reordered data.
|
||||
|
@ -142,6 +142,15 @@ void BinarySection::emitAsData(MCStreamer &Streamer,
|
||||
Streamer.emitLabel(BC.Ctx->getOrCreateSymbol("__hot_data_end"));
|
||||
}
|
||||
|
||||
uint64_t BinarySection::write(raw_ostream &OS) const {
|
||||
const uint64_t NumValidContentBytes =
|
||||
std::min<uint64_t>(getOutputContents().size(), getOutputSize());
|
||||
OS.write(getOutputContents().data(), NumValidContentBytes);
|
||||
if (getOutputSize() > NumValidContentBytes)
|
||||
OS.write_zeros(getOutputSize() - NumValidContentBytes);
|
||||
return getOutputSize();
|
||||
}
|
||||
|
||||
void BinarySection::flushPendingRelocations(raw_pwrite_stream &OS,
|
||||
SymbolResolverFuncTy Resolver) {
|
||||
if (PendingRelocations.empty() && Patches.empty())
|
||||
|
@ -3887,6 +3887,43 @@ void RewriteInstance::mapCodeSections(BOLTLinker::SectionMapper MapSection) {
|
||||
|
||||
void RewriteInstance::mapAllocatableSections(
|
||||
BOLTLinker::SectionMapper MapSection) {
|
||||
|
||||
if (opts::UseOldText || opts::StrictMode) {
|
||||
auto tryRewriteSection = [&](BinarySection &OldSection,
|
||||
BinarySection &NewSection) {
|
||||
if (OldSection.getSize() < NewSection.getOutputSize())
|
||||
return;
|
||||
|
||||
BC->outs() << "BOLT-INFO: rewriting " << OldSection.getName()
|
||||
<< " in-place\n";
|
||||
|
||||
NewSection.setOutputAddress(OldSection.getAddress());
|
||||
NewSection.setOutputFileOffset(OldSection.getInputFileOffset());
|
||||
MapSection(NewSection, OldSection.getAddress());
|
||||
|
||||
// Pad contents with zeros.
|
||||
NewSection.addPadding(OldSection.getSize() - NewSection.getOutputSize());
|
||||
|
||||
// Prevent the original section name from appearing in the section header
|
||||
// table.
|
||||
OldSection.setAnonymous(true);
|
||||
};
|
||||
|
||||
if (EHFrameSection) {
|
||||
BinarySection *NewEHFrameSection =
|
||||
getSection(getNewSecPrefix() + getEHFrameSectionName());
|
||||
assert(NewEHFrameSection && "New contents expected for .eh_frame");
|
||||
tryRewriteSection(*EHFrameSection, *NewEHFrameSection);
|
||||
}
|
||||
BinarySection *EHSection = getSection(".gcc_except_table");
|
||||
BinarySection *NewEHSection =
|
||||
getSection(getNewSecPrefix() + ".gcc_except_table");
|
||||
if (EHSection) {
|
||||
assert(NewEHSection && "New contents expected for .gcc_except_table");
|
||||
tryRewriteSection(*EHSection, *NewEHSection);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate read-only sections first, then writable sections.
|
||||
enum : uint8_t { ST_READONLY, ST_READWRITE };
|
||||
for (uint8_t SType = ST_READONLY; SType <= ST_READWRITE; ++SType) {
|
||||
@ -4164,7 +4201,6 @@ void RewriteInstance::rewriteNoteSections() {
|
||||
// New section size.
|
||||
uint64_t Size = 0;
|
||||
bool DataWritten = false;
|
||||
uint8_t *SectionData = nullptr;
|
||||
// Copy over section contents unless it's one of the sections we overwrite.
|
||||
if (!willOverwriteSection(SectionName)) {
|
||||
Size = Section.sh_size;
|
||||
@ -4196,12 +4232,7 @@ void RewriteInstance::rewriteNoteSections() {
|
||||
if (BSec->getAllocAddress()) {
|
||||
assert(!DataWritten && "Writing section twice.");
|
||||
(void)DataWritten;
|
||||
SectionData = BSec->getOutputData();
|
||||
|
||||
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " << (Size ? "appending" : "writing")
|
||||
<< " contents to section " << SectionName << '\n');
|
||||
OS.write(reinterpret_cast<char *>(SectionData), BSec->getOutputSize());
|
||||
Size += BSec->getOutputSize();
|
||||
Size += BSec->write(OS);
|
||||
}
|
||||
|
||||
BSec->setOutputFileOffset(NextAvailableOffset);
|
||||
@ -4232,8 +4263,7 @@ void RewriteInstance::rewriteNoteSections() {
|
||||
<< " of size " << Section.getOutputSize() << " at offset 0x"
|
||||
<< Twine::utohexstr(Section.getOutputFileOffset()) << '\n');
|
||||
|
||||
OS.write(Section.getOutputContents().data(), Section.getOutputSize());
|
||||
NextAvailableOffset += Section.getOutputSize();
|
||||
NextAvailableOffset += Section.write(OS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4347,6 +4377,10 @@ RewriteInstance::getOutputSections(ELFObjectFile<ELFT> *File,
|
||||
BinarySection *BinSec = BC->getSectionForSectionRef(SecRef);
|
||||
assert(BinSec && "Matching BinarySection should exist.");
|
||||
|
||||
// Exclude anonymous sections.
|
||||
if (BinSec->isAnonymous())
|
||||
continue;
|
||||
|
||||
addSection(Section, *BinSec);
|
||||
}
|
||||
|
||||
@ -5699,8 +5733,8 @@ void RewriteInstance::rewriteFile() {
|
||||
<< Twine::utohexstr(Section.getAllocAddress()) << "\n of size "
|
||||
<< Section.getOutputSize() << "\n at offset "
|
||||
<< Section.getOutputFileOffset() << '\n';
|
||||
OS.pwrite(reinterpret_cast<const char *>(Section.getOutputData()),
|
||||
Section.getOutputSize(), Section.getOutputFileOffset());
|
||||
OS.seek(Section.getOutputFileOffset());
|
||||
Section.write(OS);
|
||||
}
|
||||
|
||||
for (BinarySection &Section : BC->allocatableSections())
|
||||
|
8
bolt/test/eh-frame-overwrite.test
Normal file
8
bolt/test/eh-frame-overwrite.test
Normal file
@ -0,0 +1,8 @@
|
||||
# Check that llvm-bolt can overwrite .eh_frame section in-place.
|
||||
|
||||
REQUIRES: system-linux
|
||||
|
||||
RUN: %clang %cflags %p/Inputs/hello.c -o %t -Wl,-q
|
||||
RUN: llvm-bolt %t -o %t.bolt --strict | FileCheck %s
|
||||
|
||||
CHECK: rewriting .eh_frame in-place
|
Loading…
x
Reference in New Issue
Block a user