[BOLT] Support adding new non-allocatable sections.

Summary:
We had the ability to add allocatable sections before. This diff
expands this capability to non-allocatable sections.

(cherry picked from FBD5082018)
This commit is contained in:
Maksim Panchenko
2017-05-16 17:29:31 -07:00
parent 3adb52d80e
commit 69b586326c
3 changed files with 105 additions and 45 deletions

View File

@@ -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());

View File

@@ -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<const char *>(SI.AllocAddress), SI.Size);
NextAvailableOffset += SI.Size;
}
}
template <typename ELFT>
void RewriteInstance::writeStringTable(ELFObjectFile<ELFT> *File) {
void RewriteInstance::finalizeSectionStringTable(ELFObjectFile<ELFT> *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<ELFT> *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<uint64_t>(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<ELFT> *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<ELFT> *File) {
OS.write(reinterpret_cast<const char *>(&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<Elf_Shdr> SectionsToRewrite;
for (auto &SMII : EFMM->SectionMapInfo) {
const auto &SectionName = SMII.first;
@@ -2829,7 +2855,7 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile<ELFT> *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<ELFT> *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<ELFT> *File) {
continue;
if (Section.sh_flags & ELF::SHF_ALLOC)
continue;
if (Section.sh_type == ELF::SHT_RELA) {
--SectionCountDelta;
continue;
}
ErrorOr<StringRef> 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<const char *>(&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<const char *>(&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<ELFT> *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<const char *>(&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);

View File

@@ -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<std::string, std::unique_ptr<BinaryPatcher>> SectionPatchers;
/// [old section index] -> [new section index] map. Used for adjusting
/// referenced section indices.
std::vector<uint64_t> NewSectionIndex;
uint64_t NewTextSectionStartAddress{0};