diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 409835537fde..065260936e70 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -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(&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(&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 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(&NewTextPhdr), - sizeof(NewTextPhdr)); - if (NewWritableSegmentSize) { - ELF64LEPhdrTy NewWritablePhdr = createNewWritableSectionsPhdr(); - OS.write(reinterpret_cast(&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(&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(&NewTextPhdr), sizeof(NewTextPhdr)); - if (NewWritableSegmentSize) { - ELF64LEPhdrTy NewWritablePhdr = createNewWritableSectionsPhdr(); - OS.write(reinterpret_cast(&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 {