forked from OSchip/llvm-project
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:
parent
c98741c79e
commit
55b169bf5d
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue