[BOLT] Refactor patchELFPHDRTable() (#90290)

Mostly NFC accept for one assertion that was converted into an error.
This commit is contained in:
Maksim Panchenko
2024-04-26 16:29:42 -07:00
committed by GitHub
parent ad2816e734
commit 3ec858bc5d

View File

@@ -3926,11 +3926,6 @@ void RewriteInstance::patchELFPHDRTable() {
OS.seek(PHDRTableOffset);
bool ModdedGnuStack = false;
(void)ModdedGnuStack;
bool AddedSegment = false;
(void)AddedSegment;
auto createNewTextPhdr = [&]() {
ELF64LEPhdrTy NewPhdr;
NewPhdr.p_type = ELF::PT_LOAD;
@@ -3946,38 +3941,51 @@ void RewriteInstance::patchELFPHDRTable() {
NewPhdr.p_filesz = NewTextSegmentSize;
NewPhdr.p_memsz = NewTextSegmentSize;
NewPhdr.p_flags = ELF::PF_X | ELF::PF_R;
// FIXME: Currently instrumentation is experimental and the runtime data
// is emitted with code, thus everything needs to be writable
if (opts::Instrument)
if (opts::Instrument) {
// FIXME: Currently instrumentation is experimental and the runtime data
// is emitted with code, thus everything needs to be writable.
NewPhdr.p_flags |= ELF::PF_W;
}
NewPhdr.p_align = BC->PageAlign;
return NewPhdr;
};
auto createNewWritableSectionsPhdr = [&]() {
ELF64LEPhdrTy NewPhdr;
NewPhdr.p_type = ELF::PT_LOAD;
NewPhdr.p_offset = getFileOffsetForAddress(NewWritableSegmentAddress);
NewPhdr.p_vaddr = NewWritableSegmentAddress;
NewPhdr.p_paddr = NewWritableSegmentAddress;
NewPhdr.p_filesz = NewWritableSegmentSize;
NewPhdr.p_memsz = NewWritableSegmentSize;
NewPhdr.p_align = BC->RegularPageSize;
NewPhdr.p_flags = ELF::PF_R | ELF::PF_W;
return NewPhdr;
auto writeNewSegmentPhdrs = [&]() {
ELF64LE::Phdr NewTextPhdr = createNewTextPhdr();
OS.write(reinterpret_cast<const char *>(&NewTextPhdr), sizeof(NewTextPhdr));
if (NewWritableSegmentSize) {
ELF64LEPhdrTy NewPhdr;
NewPhdr.p_type = ELF::PT_LOAD;
NewPhdr.p_offset = getFileOffsetForAddress(NewWritableSegmentAddress);
NewPhdr.p_vaddr = NewWritableSegmentAddress;
NewPhdr.p_paddr = NewWritableSegmentAddress;
NewPhdr.p_filesz = NewWritableSegmentSize;
NewPhdr.p_memsz = NewWritableSegmentSize;
NewPhdr.p_align = BC->RegularPageSize;
NewPhdr.p_flags = ELF::PF_R | ELF::PF_W;
OS.write(reinterpret_cast<const char *>(&NewPhdr), sizeof(NewPhdr));
}
};
bool ModdedGnuStack = false;
bool AddedSegment = false;
// Copy existing program headers with modifications.
for (const ELF64LE::Phdr &Phdr : cantFail(Obj.program_headers())) {
ELF64LE::Phdr NewPhdr = Phdr;
if (PHDRTableAddress && Phdr.p_type == ELF::PT_PHDR) {
NewPhdr.p_offset = PHDRTableOffset;
NewPhdr.p_vaddr = PHDRTableAddress;
NewPhdr.p_paddr = PHDRTableAddress;
NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum;
NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
} else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
switch (Phdr.p_type) {
case ELF::PT_PHDR:
if (PHDRTableAddress) {
NewPhdr.p_offset = PHDRTableOffset;
NewPhdr.p_vaddr = PHDRTableAddress;
NewPhdr.p_paddr = PHDRTableAddress;
NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum;
NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum;
}
break;
case ELF::PT_GNU_EH_FRAME: {
ErrorOr<BinarySection &> EHFrameHdrSec = BC->getUniqueSectionByName(
getNewSecPrefix() + getEHFrameHdrSectionName());
if (EHFrameHdrSec && EHFrameHdrSec->isAllocatable() &&
@@ -3988,37 +3996,36 @@ void RewriteInstance::patchELFPHDRTable() {
NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize();
NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize();
}
} else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) {
NewPhdr = createNewTextPhdr();
ModdedGnuStack = true;
} else if (!opts::UseGnuStack && Phdr.p_type == ELF::PT_DYNAMIC) {
// Insert the new header before DYNAMIC.
ELF64LE::Phdr NewTextPhdr = createNewTextPhdr();
OS.write(reinterpret_cast<const char *>(&NewTextPhdr),
sizeof(NewTextPhdr));
if (NewWritableSegmentSize) {
ELF64LEPhdrTy NewWritablePhdr = createNewWritableSectionsPhdr();
OS.write(reinterpret_cast<const char *>(&NewWritablePhdr),
sizeof(NewWritablePhdr));
break;
}
case ELF::PT_GNU_STACK:
if (opts::UseGnuStack) {
// Overwrite the header with the new text segment header.
NewPhdr = createNewTextPhdr();
ModdedGnuStack = true;
}
AddedSegment = true;
break;
case ELF::PT_DYNAMIC:
if (!opts::UseGnuStack) {
// Insert new headers before DYNAMIC.
writeNewSegmentPhdrs();
AddedSegment = true;
}
break;
}
OS.write(reinterpret_cast<const char *>(&NewPhdr), sizeof(NewPhdr));
}
if (!opts::UseGnuStack && !AddedSegment) {
// Append the new header to the end of the table.
ELF64LE::Phdr NewTextPhdr = createNewTextPhdr();
OS.write(reinterpret_cast<const char *>(&NewTextPhdr), sizeof(NewTextPhdr));
if (NewWritableSegmentSize) {
ELF64LEPhdrTy NewWritablePhdr = createNewWritableSectionsPhdr();
OS.write(reinterpret_cast<const char *>(&NewWritablePhdr),
sizeof(NewWritablePhdr));
}
// Append new headers to the end of the table.
writeNewSegmentPhdrs();
}
assert((!opts::UseGnuStack || ModdedGnuStack) &&
"could not find GNU_STACK program header to modify");
if (opts::UseGnuStack && !ModdedGnuStack) {
BC->errs()
<< "BOLT-ERROR: could not find PT_GNU_STACK program header to modify\n";
exit(1);
}
}
namespace {