Move writeTo to OutputSectionCommand.

This reduces how many times we have to map from OutputSection to
OutputSectionCommand. It is a required step to moving
clearOutputSections earlier.

In order to always use writeTo in OutputSectionCommand we have to call
fabricateDefaultCommands for -r links and move section compression
after it.

llvm-svn: 303784
This commit is contained in:
Rafael Espindola 2017-05-24 18:08:04 +00:00
parent c98741c79e
commit 55b169bf5d
6 changed files with 118 additions and 103 deletions

View File

@ -20,6 +20,8 @@
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
@ -198,6 +200,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind;
}
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
memcpy(Buf + I, &Filler, 4);
memcpy(Buf + I, &Filler, Size - I);
}
bool InputSectionDescription::classof(const BaseCommand *C) {
return C->Kind == InputSectionKind;
}
@ -1032,10 +1043,12 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
return I->second;
}
Optional<uint32_t> LinkerScript::getFiller(OutputSection *Sec) {
if (OutputSectionCommand *Cmd = getCmd(Sec))
return Cmd->Filler;
return None;
uint32_t OutputSectionCommand::getFiller() {
if (Filler)
return *Filler;
if (Sec->Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
}
static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
@ -1051,11 +1064,45 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
llvm_unreachable("unsupported Size argument");
}
void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) {
if (OutputSectionCommand *Cmd = getCmd(Sec))
for (BaseCommand *Base : Cmd->Commands)
if (auto *Data = dyn_cast<BytesDataCommand>(Base))
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
Sec->Loc = Buf;
// We may have already rendered compressed content when using
// -compress-debug-sections option. Write it together with header.
if (!Sec->CompressedData.empty()) {
memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size());
memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(),
Sec->CompressedData.size());
return;
}
// Write leading padding.
ArrayRef<InputSection *> Sections = Sec->Sections;
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler);
parallelForEachN(0, Sections.size(), [=](size_t I) {
InputSection *IS = Sections[I];
IS->writeTo<ELFT>(Buf);
// Fill gaps between sections.
if (Filler) {
uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
End = Buf + Sec->Size;
else
End = Buf + Sections[I + 1]->OutSecOff;
fill(Start, End - Start, Filler);
}
});
// Linker scripts may have BYTE()-family commands with which you
// can write arbitrary bytes to the output. Process them if any.
for (BaseCommand *Base : Commands)
if (auto *Data = dyn_cast<BytesDataCommand>(Base))
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
bool LinkerScript::hasLMA(OutputSection *Sec) {
@ -1102,3 +1149,8 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
return 0;
}
template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf);
template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf);
template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf);
template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf);

View File

@ -130,6 +130,9 @@ struct OutputSectionCommand : BaseCommand {
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
template <class ELFT> void writeTo(uint8_t *Buf);
uint32_t getFiller();
};
// This struct represents one section match pattern in SECTIONS() command.
@ -213,7 +216,6 @@ struct ScriptConfiguration {
class LinkerScript final {
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
OutputSectionCommand *getCmd(OutputSection *Sec) const;
void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec);
@ -244,6 +246,7 @@ class LinkerScript final {
MemoryRegion *CurMemRegion = nullptr;
public:
OutputSectionCommand *getCmd(OutputSection *Sec) const;
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
uint64_t getDot() { return Dot; }
OutputSection *getOutputSection(const Twine &Loc, StringRef S);
@ -263,7 +266,6 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
llvm::Optional<uint32_t> getFiller(OutputSection *Sec);
bool hasLMA(OutputSection *Sec);
bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
@ -272,7 +274,6 @@ public:
void synchronize();
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
void writeDataBytes(OutputSection *Sec, uint8_t *Buf);
void addSymbol(SymbolAssignment *Cmd);
void processCommands(OutputSectionFactory &Factory);

View File

@ -103,7 +103,7 @@ template <class ELFT> void OutputSection::maybeCompress() {
// Write section contents to a temporary buffer and compress it.
std::vector<uint8_t> Buf(Size);
writeTo<ELFT>(Buf.data());
Script->getCmd(this)->writeTo<ELFT>(Buf.data());
if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
fatal("compress failed: " + llvm::toString(std::move(E)));
@ -259,65 +259,6 @@ void OutputSection::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors);
}
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
memcpy(Buf + I, &Filler, 4);
memcpy(Buf + I, &Filler, Size - I);
}
uint32_t OutputSection::getFiller() {
// Determine what to fill gaps between InputSections with, as specified by the
// linker script. If nothing is specified and this is an executable section,
// fall back to trap instructions to prevent bad diassembly and detect invalid
// jumps to padding.
if (Optional<uint32_t> Filler = Script->getFiller(this))
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
}
template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
Loc = Buf;
// We may have already rendered compressed content when using
// -compress-debug-sections option. Write it together with header.
if (!CompressedData.empty()) {
memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size());
memcpy(Buf + ZDebugHeader.size(), CompressedData.data(),
CompressedData.size());
return;
}
// Write leading padding.
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
parallelForEachN(0, Sections.size(), [=](size_t I) {
InputSection *Sec = Sections[I];
Sec->writeTo<ELFT>(Buf);
// Fill gaps between sections.
if (Filler) {
uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
End = Buf + Size;
else
End = Buf + Sections[I + 1]->OutSecOff;
fill(Start, End - Start, Filler);
}
});
// Linker scripts may have BYTE()-family commands with which you
// can write arbitrary bytes to the output. Process them if any.
Script->writeDataBytes(this, Buf);
}
static uint64_t getOutFlags(InputSectionBase *S) {
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
}
@ -484,8 +425,3 @@ template void OutputSection::maybeCompress<ELF32LE>();
template void OutputSection::maybeCompress<ELF32BE>();
template void OutputSection::maybeCompress<ELF64LE>();
template void OutputSection::maybeCompress<ELF64BE>();
template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);

View File

@ -82,8 +82,6 @@ public:
void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
uint32_t getFiller();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void finalize();
template <class ELFT> void maybeCompress();
void assignOffsets();

View File

@ -2175,11 +2175,10 @@ MipsRldMapSection::MipsRldMapSection()
void MipsRldMapSection::writeTo(uint8_t *Buf) {
// Apply filler from linker script.
Optional<uint32_t> Fill = Script->getFiller(this->OutSec);
if (!Fill || *Fill == 0)
uint64_t Filler = Script->getCmd(this->OutSec)->getFiller();
if (Filler == 0)
return;
uint64_t Filler = *Fill;
Filler = (Filler << 32) | Filler;
memcpy(Buf, &Filler, getSize());
}

View File

@ -81,6 +81,7 @@ private:
void addStartStopSymbols(OutputSection *Sec);
uint64_t getEntryAddr();
OutputSection *findSection(StringRef Name);
OutputSectionCommand *findSectionInScript(StringRef Name);
std::vector<PhdrEntry> Phdrs;
@ -254,13 +255,21 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
if (!Script->Opt.HasSections) {
if (!Config->Relocatable)
fixSectionAlignments();
Script->fabricateDefaultCommands();
}
// If -compressed-debug-sections is specified, we need to compress
// .debug_* sections. Do it right now because it changes the size of
// output sections.
parallelForEach(OutputSections.begin(), OutputSections.end(),
[](OutputSection *S) { S->maybeCompress<ELFT>(); });
if (Config->Relocatable) {
assignFileOffsets();
} else {
if (!Script->Opt.HasSections) {
fixSectionAlignments();
Script->fabricateDefaultCommands();
}
Script->synchronize();
Script->assignAddresses(Phdrs);
@ -1246,12 +1255,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
// If -compressed-debug-sections is specified, we need to compress
// .debug_* sections. Do it right now because it changes the size of
// output sections.
parallelForEach(OutputSections.begin(), OutputSections.end(),
[](OutputSection *S) { S->maybeCompress<ELFT>(); });
// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
@ -1304,6 +1307,15 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
}
template <class ELFT>
OutputSectionCommand *Writer<ELFT>::findSectionInScript(StringRef Name) {
for (BaseCommand *Base : Script->Opt.Commands)
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (Cmd->Name == Name)
return Cmd;
return nullptr;
}
template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections)
if (Sec->Name == Name)
@ -1743,9 +1755,14 @@ template <class ELFT> void Writer<ELFT>::openFile() {
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart();
for (OutputSection *Sec : OutputSections)
for (BaseCommand *Base : Script->Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
OutputSection *Sec = Cmd->Sec;
if (Sec->Flags & SHF_ALLOC)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
Cmd->writeTo<ELFT>(Buf + Sec->Offset);
}
}
// Write section contents to a mmap'ed file.
@ -1754,10 +1771,10 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// PPC64 needs to process relocations in the .opd section
// before processing relocations in code-containing sections.
Out::Opd = findSection(".opd");
if (Out::Opd) {
if (auto *OpdCmd = findSectionInScript(".opd")) {
Out::Opd = OpdCmd->Sec;
Out::OpdBuf = Buf + Out::Opd->Offset;
Out::Opd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
}
OutputSection *EhFrameHdr =
@ -1766,19 +1783,31 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// In -r or -emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
// section while doing it.
for (OutputSection *Sec : OutputSections)
for (BaseCommand *Base : Script->Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
OutputSection *Sec = Cmd->Sec;
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
Cmd->writeTo<ELFT>(Buf + Sec->Offset);
}
for (OutputSection *Sec : OutputSections)
for (BaseCommand *Base : Script->Opt.Commands) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
OutputSection *Sec = Cmd->Sec;
if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
Sec->Type != SHT_RELA)
Sec->writeTo<ELFT>(Buf + Sec->Offset);
Cmd->writeTo<ELFT>(Buf + Sec->Offset);
}
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
if (EhFrameHdr && !EhFrameHdr->Sections.empty())
EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
if (EhFrameHdr && !EhFrameHdr->Sections.empty()) {
OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
}
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {