[BOLT] Refactor patchELFPHDRTable() (#90290)
Mostly NFC accept for one assertion that was converted into an error.
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user