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 "SymbolTable.h"
#include "Symbols.h" #include "Symbols.h"
#include "SyntheticSections.h" #include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
#include "Writer.h" #include "Writer.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
@ -198,6 +200,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) {
return C->Kind == OutputSectionKind; 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) { bool InputSectionDescription::classof(const BaseCommand *C) {
return C->Kind == InputSectionKind; return C->Kind == InputSectionKind;
} }
@ -1032,10 +1043,12 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {
return I->second; return I->second;
} }
Optional<uint32_t> LinkerScript::getFiller(OutputSection *Sec) { uint32_t OutputSectionCommand::getFiller() {
if (OutputSectionCommand *Cmd = getCmd(Sec)) if (Filler)
return Cmd->Filler; return *Filler;
return None; if (Sec->Flags & SHF_EXECINSTR)
return Target->TrapInstr;
return 0;
} }
static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
@ -1051,9 +1064,43 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
llvm_unreachable("unsupported Size argument"); llvm_unreachable("unsupported Size argument");
} }
void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) { template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
if (OutputSectionCommand *Cmd = getCmd(Sec)) Sec->Loc = Buf;
for (BaseCommand *Base : Cmd->Commands)
// 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)) if (auto *Data = dyn_cast<BytesDataCommand>(Base))
writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
} }
@ -1102,3 +1149,8 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
return 0; 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; ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location; std::string Location;
std::string MemoryRegionName; std::string MemoryRegionName;
template <class ELFT> void writeTo(uint8_t *Buf);
uint32_t getFiller();
}; };
// This struct represents one section match pattern in SECTIONS() command. // This struct represents one section match pattern in SECTIONS() command.
@ -213,7 +216,6 @@ struct ScriptConfiguration {
class LinkerScript final { class LinkerScript final {
llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand; llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand;
OutputSectionCommand *getCmd(OutputSection *Sec) const;
void assignSymbol(SymbolAssignment *Cmd, bool InSec); void assignSymbol(SymbolAssignment *Cmd, bool InSec);
void setDot(Expr E, const Twine &Loc, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec);
@ -244,6 +246,7 @@ class LinkerScript final {
MemoryRegion *CurMemRegion = nullptr; MemoryRegion *CurMemRegion = nullptr;
public: public:
OutputSectionCommand *getCmd(OutputSection *Sec) const;
bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
uint64_t getDot() { return Dot; } uint64_t getDot() { return Dot; }
OutputSection *getOutputSection(const Twine &Loc, StringRef S); OutputSection *getOutputSection(const Twine &Loc, StringRef S);
@ -263,7 +266,6 @@ public:
std::vector<PhdrEntry> createPhdrs(); std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection(); bool ignoreInterpSection();
llvm::Optional<uint32_t> getFiller(OutputSection *Sec);
bool hasLMA(OutputSection *Sec); bool hasLMA(OutputSection *Sec);
bool shouldKeep(InputSectionBase *S); bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd); void assignOffsets(OutputSectionCommand *Cmd);
@ -272,7 +274,6 @@ public:
void synchronize(); void synchronize();
void assignAddresses(std::vector<PhdrEntry> &Phdrs); void assignAddresses(std::vector<PhdrEntry> &Phdrs);
void writeDataBytes(OutputSection *Sec, uint8_t *Buf);
void addSymbol(SymbolAssignment *Cmd); void addSymbol(SymbolAssignment *Cmd);
void processCommands(OutputSectionFactory &Factory); 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. // Write section contents to a temporary buffer and compress it.
std::vector<uint8_t> Buf(Size); 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)) if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
fatal("compress failed: " + llvm::toString(std::move(E))); fatal("compress failed: " + llvm::toString(std::move(E)));
@ -259,65 +259,6 @@ void OutputSection::sortCtorsDtors() {
std::stable_sort(Sections.begin(), Sections.end(), compCtors); 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) { static uint64_t getOutFlags(InputSectionBase *S) {
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED; 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<ELF32BE>();
template void OutputSection::maybeCompress<ELF64LE>(); template void OutputSection::maybeCompress<ELF64LE>();
template void OutputSection::maybeCompress<ELF64BE>(); 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 sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini(); void sortInitFini();
void sortCtorsDtors(); void sortCtorsDtors();
uint32_t getFiller();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void finalize(); template <class ELFT> void finalize();
template <class ELFT> void maybeCompress(); template <class ELFT> void maybeCompress();
void assignOffsets(); void assignOffsets();

View File

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

View File

@ -81,6 +81,7 @@ private:
void addStartStopSymbols(OutputSection *Sec); void addStartStopSymbols(OutputSection *Sec);
uint64_t getEntryAddr(); uint64_t getEntryAddr();
OutputSection *findSection(StringRef Name); OutputSection *findSection(StringRef Name);
OutputSectionCommand *findSectionInScript(StringRef Name);
std::vector<PhdrEntry> Phdrs; std::vector<PhdrEntry> Phdrs;
@ -254,13 +255,21 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount) if (ErrorCount)
return; return;
if (Config->Relocatable) {
assignFileOffsets();
} else {
if (!Script->Opt.HasSections) { if (!Script->Opt.HasSections) {
if (!Config->Relocatable)
fixSectionAlignments(); fixSectionAlignments();
Script->fabricateDefaultCommands(); 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 {
Script->synchronize(); Script->synchronize();
Script->assignAddresses(Phdrs); Script->assignAddresses(Phdrs);
@ -1246,12 +1255,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (OutputSection *Sec : OutputSections) for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>(); 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 // createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); }); [](SyntheticSection *SS) { SS->postThunkContents(); });
@ -1304,6 +1307,15 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); 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) { template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections) for (OutputSection *Sec : OutputSections)
if (Sec->Name == Name) if (Sec->Name == Name)
@ -1743,9 +1755,14 @@ template <class ELFT> void Writer<ELFT>::openFile() {
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() { template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart(); 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) 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. // 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 // PPC64 needs to process relocations in the .opd section
// before processing relocations in code-containing sections. // before processing relocations in code-containing sections.
Out::Opd = findSection(".opd"); if (auto *OpdCmd = findSectionInScript(".opd")) {
if (Out::Opd) { Out::Opd = OpdCmd->Sec;
Out::OpdBuf = Buf + Out::Opd->Offset; 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 = 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 // 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 // ELf_Rel targets we might find out that we need to modify the relocated
// section while doing it. // 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) 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 && if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
Sec->Type != SHT_RELA) 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 // The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written. // it should be written after .eh_frame is written.
if (EhFrameHdr && !EhFrameHdr->Sections.empty()) if (EhFrameHdr && !EhFrameHdr->Sections.empty()) {
EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset); OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
}
} }
template <class ELFT> void Writer<ELFT>::writeBuildId() { template <class ELFT> void Writer<ELFT>::writeBuildId() {