diff --git a/bolt/DWARFRewriter.cpp b/bolt/DWARFRewriter.cpp index c8726a30e7c7..1b817491796d 100644 --- a/bolt/DWARFRewriter.cpp +++ b/bolt/DWARFRewriter.cpp @@ -422,7 +422,7 @@ void RewriteInstance::generateDebugRanges() { } const auto &DebugRangesContents = OS.str(); - // Free'd by ExecutableFileMemoryManager. + // Freed by ExecutableFileMemoryManager. uint8_t *SectionData = new uint8_t[DebugRangesContents.size()]; memcpy(SectionData, DebugRangesContents.data(), DebugRangesContents.size()); diff --git a/bolt/RewriteInstance.cpp b/bolt/RewriteInstance.cpp index 22ebaba1b021..7c04024a755c 100644 --- a/bolt/RewriteInstance.cpp +++ b/bolt/RewriteInstance.cpp @@ -2604,6 +2604,9 @@ namespace { uint64_t appendPadding(raw_pwrite_stream &OS, uint64_t Offset, uint64_t Alignment) { + if (!Alignment) + return Offset; + const auto PaddingSize = OffsetToAlignment(Offset, Alignment); for (unsigned I = 0; I < PaddingSize; ++I) OS.write((unsigned char)0); @@ -2716,12 +2719,30 @@ void RewriteInstance::rewriteNoteSections() { NextAvailableOffset += Size; } + + // Write new note sections. + for (auto &SII : EFMM->NoteSectionInfo) { + auto &SI = SII.second; + if (SI.FileOffset || !SI.AllocAddress) + continue; + + assert(SI.PendingRelocs.empty() && "cannot have pending relocs"); + + NextAvailableOffset = appendPadding(OS, NextAvailableOffset, SI.Alignment); + SI.FileOffset = NextAvailableOffset; + + DEBUG(dbgs() << "BOLT-DEBUG: writing out new section " << SII.first + << " of size " << SI.Size << " at offset 0x" + << Twine::utohexstr(SI.FileOffset) << '\n'); + + OS.write(reinterpret_cast(SI.AllocAddress), SI.Size); + NextAvailableOffset += SI.Size; + } } template -void RewriteInstance::writeStringTable(ELFObjectFile *File) { +void RewriteInstance::finalizeSectionStringTable(ELFObjectFile *File) { auto *Obj = File->getELFFile(); - auto &OS = Out->os(); // Pre-populate section header string table. for (auto &Section : Obj->sections()) { @@ -2734,16 +2755,22 @@ void RewriteInstance::writeStringTable(ELFObjectFile *File) { for (auto &SMII : EFMM->SectionMapInfo) { SHStrTab.add(SMII.first); } + for (auto &SMII : EFMM->NoteSectionInfo) { + SHStrTab.add(SMII.first); + } SHStrTab.finalize(StringTableBuilder::ELF); - auto SII = EFMM->NoteSectionInfo.find(".shstrtab"); - assert(SII != EFMM->NoteSectionInfo.end() && "cannot find .shstrtab"); - auto &SI = SII->second; - SI.FileOffset = OS.tell(); - SI.Size = SHStrTab.data().size(); - - // Write data for the table. - OS << SHStrTab.data(); + const auto SHStrTabSize = SHStrTab.data().size(); + uint8_t *DataCopy = new uint8_t[SHStrTabSize]; + memcpy(DataCopy, SHStrTab.data().data(), SHStrTabSize); + EFMM->NoteSectionInfo[".shstrtab"] = + SectionInfo(reinterpret_cast(DataCopy), + SHStrTabSize, + /*Alignment*/1, + /*IsCode=*/false, + /*IsReadOnly=*/false, + /*IsLocal=*/false); + EFMM->NoteSectionInfo[".shstrtab"].IsStrTab = true; } // Rewrite section header table inserting new entries as needed. The sections @@ -2751,10 +2778,12 @@ void RewriteInstance::writeStringTable(ELFObjectFile *File) { // so we are placing it at the end of the binary. // // As we rewrite entries we need to track how many sections were inserted -// as it changes the sh_link value. +// as it changes the sh_link value. We map old indices to new ones for +// existing sections. // // The following are assumptions about file modifications: -// * There are no modifications done to existing allocatable sections. +// * There are no modifications done to address and/or size of existing +// allocatable sections. // * All new allocatable sections are written immediately after existing // allocatable sections. // * There could be modifications done to non-allocatable sections, e.g. @@ -2811,12 +2840,9 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { OS.write(reinterpret_cast(&NewSection), sizeof(NewSection)); NewSectionIndex[std::distance(Obj->section_begin(), &Section)] = CurrentSectionIndex++; - } // Create entries for new allocatable sections. - // - // Skip sections we overwrite in-place (like data sections). std::vector SectionsToRewrite; for (auto &SMII : EFMM->SectionMapInfo) { const auto &SectionName = SMII.first; @@ -2829,7 +2855,7 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { continue; } if (opts::Verbosity >= 1) - outs() << "BOLT-INFO: writing section header for " << SMII.first << '\n'; + outs() << "BOLT-INFO: writing section header for " << SectionName << '\n'; Elf_Shdr NewSection; NewSection.sh_name = SHStrTab.getOffset(SectionName); NewSection.sh_type = ELF::SHT_PROGBITS; @@ -2859,7 +2885,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { ++CurrentSectionIndex; } - int64_t NumNewSections = SectionsToRewrite.size(); + int64_t SectionCountDelta = SectionsToRewrite.size(); + uint64_t LastFileOffset = 0; // Copy over entries for non-allocatable sections performing necessary // adjustments. @@ -2868,46 +2895,77 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { continue; if (Section.sh_flags & ELF::SHF_ALLOC) continue; + if (Section.sh_type == ELF::SHT_RELA) { + --SectionCountDelta; + continue; + } ErrorOr SectionName = Obj->getSectionName(&Section); check_error(SectionName.getError(), "cannot get section name"); - if (Section.sh_type == ELF::SHT_RELA) { - if (opts::Verbosity) - outs() << "BOLT-INFO: omitting section header for relocation section " - << *SectionName << '\n'; - --NumNewSections; - continue; - } - auto SII = EFMM->NoteSectionInfo.find(*SectionName); assert(SII != EFMM->NoteSectionInfo.end() && "missing section info for non-allocatable section"); + const auto &SI = SII->second; auto NewSection = Section; - NewSection.sh_offset = SII->second.FileOffset; - NewSection.sh_size = SII->second.Size; + NewSection.sh_offset = SI.FileOffset; + NewSection.sh_size = SI.Size; NewSection.sh_name = SHStrTab.getOffset(*SectionName); // Adjust sh_link for sections that use it. if (Section.sh_link) - NewSection.sh_link = Section.sh_link + NumNewSections; + NewSection.sh_link = Section.sh_link + SectionCountDelta; // Adjust sh_info for relocation sections. if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) { if (Section.sh_info) - NewSection.sh_info = Section.sh_info + NumNewSections; + NewSection.sh_info = Section.sh_info + SectionCountDelta; } OS.write(reinterpret_cast(&NewSection), sizeof(NewSection)); NewSectionIndex[std::distance(Obj->section_begin(), &Section)] = CurrentSectionIndex++; + + LastFileOffset = SI.FileOffset; } - // Using new section indices map updates sh_link and sh_info where needed. - // + // Create entries for new non-allocatable sections. + SectionsToRewrite.clear(); + for (auto &SII : EFMM->NoteSectionInfo) { + const auto &SectionName = SII.first; + const auto &SI = SII.second; - // New section header string table goes last. + if (SI.FileOffset <= LastFileOffset) + continue; + + if (opts::Verbosity >= 1) + outs() << "BOLT-INFO: writing section header for " << SectionName << '\n'; + Elf_Shdr NewSection; + NewSection.sh_name = SHStrTab.getOffset(SectionName); + NewSection.sh_type = (SI.IsStrTab ? ELF::SHT_STRTAB : ELF::SHT_PROGBITS); + NewSection.sh_addr = 0; + NewSection.sh_offset = SI.FileOffset; + NewSection.sh_size = SI.Size; + NewSection.sh_entsize = 0; + NewSection.sh_flags = 0; + NewSection.sh_link = 0; + NewSection.sh_info = 0; + NewSection.sh_addralign = SI.Alignment ? SI.Alignment : 1; + SectionsToRewrite.emplace_back(NewSection); + } + + // Write section header entries for new non-allocatable sections. + std::stable_sort(SectionsToRewrite.begin(), SectionsToRewrite.end(), + [] (Elf_Shdr A, Elf_Shdr B) { + return A.sh_offset < B.sh_offset; + }); + for (auto &SI : SectionsToRewrite) { + OS.write(reinterpret_cast(&SI), sizeof(SI)); + ++CurrentSectionIndex; + } + const auto AllocSectionCountDelta = SectionCountDelta; + SectionCountDelta += SectionsToRewrite.size(); // Fix ELF header. auto NewEhdr = *Obj->getHeader(); @@ -2919,8 +2977,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { NewEhdr.e_phoff = PHDRTableOffset; NewEhdr.e_phnum = Phnum; NewEhdr.e_shoff = SHTOffset; - NewEhdr.e_shnum = NewEhdr.e_shnum + NumNewSections; - NewEhdr.e_shstrndx = NewEhdr.e_shstrndx + NumNewSections; + NewEhdr.e_shnum = NewEhdr.e_shnum + SectionCountDelta; + NewEhdr.e_shstrndx = NewEhdr.e_shstrndx + AllocSectionCountDelta; OS.pwrite(reinterpret_cast(&NewEhdr), sizeof(NewEhdr), 0); assert(NewEhdr.e_shnum == CurrentSectionIndex && @@ -3291,12 +3349,12 @@ void RewriteInstance::rewriteFile() { // Patch program header table. patchELFPHDRTable(); + // Finalize memory image of section string table. + finalizeSectionStringTable(); + // Copy non-allocatable sections once allocatable part is finished. rewriteNoteSections(); - // Write string. - writeStringTable(); - if (opts::Relocs) { // Patch dynamic section/segment. patchELFDynamic(); @@ -3417,11 +3475,9 @@ uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const { } bool RewriteInstance::willOverwriteSection(StringRef SectionName) { - if (opts::UpdateDebugSections) { - for (auto &OverwriteName : DebugSectionsToOverwrite) { - if (SectionName == OverwriteName) - return true; - } + for (auto &OverwriteName : DebugSectionsToOverwrite) { + if (SectionName == OverwriteName) + return true; } auto SMII = EFMM->SectionMapInfo.find(SectionName); diff --git a/bolt/RewriteInstance.h b/bolt/RewriteInstance.h index e024c0e5247e..1253cd9cec06 100644 --- a/bolt/RewriteInstance.h +++ b/bolt/RewriteInstance.h @@ -46,6 +46,7 @@ struct SectionInfo { bool IsReadOnly{false}; /// Is the section read-only? bool IsLocal{false}; /// Is this section local to a function, and /// should only be emitted with the function? + bool IsStrTab{false}; /// Is this a string table section. uint64_t FileAddress{0}; /// Address for the output file (final address). uint64_t FileOffset{0}; /// Offset in the output file. unsigned SectionID{0}; /// Unique ID used for address mapping. @@ -309,8 +310,8 @@ private: /// Patch .rela.plt section. ELF_FUNCTION(patchELFRelaPLT); - /// Write .shstrtab. - ELF_FUNCTION(writeStringTable); + /// Finalize memory image of section header string table. + ELF_FUNCTION(finalizeSectionStringTable); /// Computes output .debug_line line table offsets for each compile unit, /// and updates stmt_list for a corresponding compile unit. @@ -392,6 +393,7 @@ private: /// When updating debug info, these are the sections we overwrite. static constexpr const char *DebugSectionsToOverwrite[] = { + ".shstrtab", ".debug_aranges", ".debug_line", ".debug_ranges", @@ -456,6 +458,8 @@ private: /// Maps section name -> patcher. std::map> SectionPatchers; + /// [old section index] -> [new section index] map. Used for adjusting + /// referenced section indices. std::vector NewSectionIndex; uint64_t NewTextSectionStartAddress{0};