summaryrefslogtreecommitdiff
path: root/ELF/LinkerScript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/LinkerScript.cpp')
-rw-r--r--ELF/LinkerScript.cpp98
1 files changed, 74 insertions, 24 deletions
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index c303f0524ad44..492b81c1fa762 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -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;
}
@@ -263,16 +274,16 @@ static bool matchConstraints(ArrayRef<InputSectionBase *> Sections,
(!IsRW && Kind == ConstraintKind::ReadOnly);
}
-static void sortSections(InputSectionBase **Begin, InputSectionBase **End,
+static void sortSections(InputSection **Begin, InputSection **End,
SortSectionPolicy K) {
if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
std::stable_sort(Begin, End, getComparator(K));
}
// Compute and remember which sections the InputSectionDescription matches.
-std::vector<InputSectionBase *>
+std::vector<InputSection *>
LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
- std::vector<InputSectionBase *> Ret;
+ std::vector<InputSection *> Ret;
// Collects all sections that satisfy constraints of Cmd.
for (const SectionPattern &Pat : Cmd->SectionPatterns) {
@@ -294,7 +305,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
!Pat.SectionPat.match(Sec->Name))
continue;
- Ret.push_back(Sec);
+ Ret.push_back(cast<InputSection>(Sec));
Sec->Assigned = true;
}
@@ -309,8 +320,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
- InputSectionBase **Begin = Ret.data() + SizeBefore;
- InputSectionBase **End = Ret.data() + Ret.size();
+ InputSection **Begin = Ret.data() + SizeBefore;
+ InputSection **End = Ret.data() + Ret.size();
if (Pat.SortOuter != SortSectionPolicy::None) {
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Begin, End, Config->SortSection);
@@ -493,7 +504,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
Sec->SectionIndex = Index;
}
auto *ISD = make<InputSectionDescription>("");
- ISD->Sections.push_back(S);
+ ISD->Sections.push_back(cast<InputSection>(S));
Cmd->Commands.push_back(ISD);
}
}
@@ -684,7 +695,6 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// '.' is assigned to, but creating these section should not have any bad
// consequeces and gives us a section to put the symbol in.
uint64_t Flags = SHF_ALLOC;
- uint32_t Type = SHT_PROGBITS;
for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {
auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
@@ -692,14 +702,13 @@ void LinkerScript::adjustSectionsBeforeSorting() {
continue;
if (OutputSection *Sec = Cmd->Sec) {
Flags = Sec->Flags;
- Type = Sec->Type;
continue;
}
if (isAllSectionDescription(*Cmd))
continue;
- auto *OutSec = make<OutputSection>(Cmd->Name, Type, Flags);
+ auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags);
OutSec->SectionIndex = I;
OutputSections->push_back(OutSec);
Cmd->Sec = OutSec;
@@ -875,20 +884,20 @@ void LinkerScript::synchronize() {
if (!Cmd)
continue;
ArrayRef<InputSection *> Sections = Cmd->Sec->Sections;
- std::vector<InputSectionBase **> ScriptSections;
- DenseSet<InputSectionBase *> ScriptSectionsSet;
+ std::vector<InputSection **> ScriptSections;
+ DenseSet<InputSection *> ScriptSectionsSet;
for (BaseCommand *Base : Cmd->Commands) {
auto *ISD = dyn_cast<InputSectionDescription>(Base);
if (!ISD)
continue;
- for (InputSectionBase *&IS : ISD->Sections) {
+ for (InputSection *&IS : ISD->Sections) {
if (IS->Live) {
ScriptSections.push_back(&IS);
ScriptSectionsSet.insert(IS);
}
}
}
- std::vector<InputSectionBase *> Missing;
+ std::vector<InputSection *> Missing;
for (InputSection *IS : Sections)
if (!ScriptSectionsSet.count(IS))
Missing.push_back(IS);
@@ -896,7 +905,7 @@ void LinkerScript::synchronize() {
auto ISD = make<InputSectionDescription>("");
ISD->Sections = Missing;
Cmd->Commands.push_back(ISD);
- for (InputSectionBase *&IS : ISD->Sections)
+ for (InputSection *&IS : ISD->Sections)
if (IS->Live)
ScriptSections.push_back(&IS);
}
@@ -1034,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) {
@@ -1053,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) {
@@ -1104,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);