summaryrefslogtreecommitdiff
path: root/ELF/LinkerScript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/LinkerScript.cpp')
-rw-r--r--ELF/LinkerScript.cpp127
1 files changed, 86 insertions, 41 deletions
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 99c464e3714c..75df2cd4bd5c 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
@@ -51,9 +52,8 @@ LinkerScript *elf::Script;
uint64_t ExprValue::getValue() const {
if (Sec) {
- if (Sec->getOutputSection())
- return alignTo(Sec->getOffset(Val) + Sec->getOutputSection()->Addr,
- Alignment);
+ if (OutputSection *OS = Sec->getOutputSection())
+ return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment);
error("unable to evaluate expression: input section " + Sec->Name +
" has no output section assigned");
}
@@ -85,29 +85,28 @@ template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) {
return Sym->body();
}
-OutputSection *LinkerScript::getOutputSection(const Twine &Loc,
- StringRef Name) {
- for (OutputSection *Sec : *OutputSections)
- if (Sec->Name == Name)
- return Sec;
-
- static OutputSection Dummy("", 0, 0);
- if (ErrorOnMissingSection)
- error(Loc + ": undefined section " + Name);
- return &Dummy;
+OutputSectionCommand *
+LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) {
+ OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
+ OutputSectionCommand *Cmd;
+ if (CmdRef && CmdRef->Location.empty()) {
+ // There was a forward reference.
+ Cmd = CmdRef;
+ } else {
+ Cmd = make<OutputSectionCommand>(Name);
+ if (!CmdRef)
+ CmdRef = Cmd;
+ }
+ Cmd->Location = Location;
+ return Cmd;
}
-// This function is essentially the same as getOutputSection(Name)->Size,
-// but it won't print out an error message if a given section is not found.
-//
-// Linker script does not create an output section if its content is empty.
-// We want to allow SIZEOF(.foo) where .foo is a section which happened to
-// be empty. That is why this function is different from getOutputSection().
-uint64_t LinkerScript::getOutputSectionSize(StringRef Name) {
- for (OutputSection *Sec : *OutputSections)
- if (Sec->Name == Name)
- return Sec->Size;
- return 0;
+OutputSectionCommand *
+LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) {
+ OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name];
+ if (!CmdRef)
+ CmdRef = make<OutputSectionCommand>(Name);
+ return CmdRef;
}
void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
@@ -291,11 +290,13 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
size_t SizeBefore = Ret.size();
for (InputSectionBase *Sec : InputSections) {
- if (!isa<InputSection>(Sec))
+ if (Sec->Assigned)
continue;
- if (Sec->Assigned)
+ if (!Sec->Live) {
+ reportDiscarded(Sec);
continue;
+ }
// For -emit-relocs we have to ignore entries like
// .rela.dyn : { *(.rela.data) }
@@ -455,7 +456,7 @@ void LinkerScript::fabricateDefaultCommands() {
// For each OutputSection that needs a VA fabricate an OutputSectionCommand
// with an InputSectionDescription describing the InputSections
for (OutputSection *Sec : *OutputSections) {
- auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
+ auto *OSCmd = createOutputSectionCommand(Sec->Name, "<internal>");
OSCmd->Sec = Sec;
SecToCommand[Sec] = OSCmd;
@@ -487,7 +488,7 @@ void LinkerScript::fabricateDefaultCommands() {
// Add sections that didn't match any sections command.
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
for (InputSectionBase *S : InputSections) {
- if (!S->Live || S->OutSec)
+ if (!S->Live || S->Parent)
continue;
StringRef Name = getOutputSectionName(S->Name);
auto I = std::find_if(
@@ -590,7 +591,7 @@ void LinkerScript::process(BaseCommand &Base) {
// It calculates and assigns the offsets for each section and also
// updates the output section size.
auto &Cmd = cast<InputSectionDescription>(Base);
- for (InputSectionBase *Sec : Cmd.Sections) {
+ for (InputSection *Sec : Cmd.Sections) {
// We tentatively added all synthetic sections at the beginning and removed
// empty ones afterwards (because there is no way to know whether they were
// going be empty or not other than actually running linker scripts.)
@@ -601,8 +602,8 @@ void LinkerScript::process(BaseCommand &Base) {
if (!Sec->Live)
continue;
- assert(CurOutSec == Sec->OutSec);
- output(cast<InputSection>(Sec));
+ assert(CurOutSec == Sec->getParent());
+ output(Sec);
}
}
@@ -842,7 +843,7 @@ void LinkerScript::placeOrphanSections() {
// representations agree on which input sections to use.
OutputSectionCommand *Cmd = getCmd(Sec);
if (!Cmd) {
- Cmd = make<OutputSectionCommand>(Name);
+ Cmd = createOutputSectionCommand(Name, "<internal>");
Opt.Commands.insert(CmdIter, Cmd);
++CmdIndex;
@@ -919,9 +920,10 @@ void LinkerScript::synchronize() {
}
}
-static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
- ArrayRef<OutputSection *> OutputSections,
- uint64_t Min) {
+static bool
+allocateHeaders(std::vector<PhdrEntry> &Phdrs,
+ ArrayRef<OutputSectionCommand *> OutputSectionCommands,
+ uint64_t Min) {
auto FirstPTLoad =
std::find_if(Phdrs.begin(), Phdrs.end(),
[](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
@@ -938,16 +940,19 @@ static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
assert(FirstPTLoad->First == Out::ElfHeader);
OutputSection *ActualFirst = nullptr;
- for (OutputSection *Sec : OutputSections) {
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
if (Sec->FirstInPtLoad == Out::ElfHeader) {
ActualFirst = Sec;
break;
}
}
if (ActualFirst) {
- for (OutputSection *Sec : OutputSections)
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
if (Sec->FirstInPtLoad == Out::ElfHeader)
Sec->FirstInPtLoad = ActualFirst;
+ }
FirstPTLoad->First = ActualFirst;
} else {
Phdrs.erase(FirstPTLoad);
@@ -961,7 +966,9 @@ static bool allocateHeaders(std::vector<PhdrEntry> &Phdrs,
return false;
}
-void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
+void LinkerScript::assignAddresses(
+ std::vector<PhdrEntry> &Phdrs,
+ ArrayRef<OutputSectionCommand *> OutputSectionCommands) {
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = 0;
ErrorOnMissingSection = true;
@@ -983,14 +990,15 @@ void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
}
uint64_t MinVA = std::numeric_limits<uint64_t>::max();
- for (OutputSection *Sec : *OutputSections) {
+ for (OutputSectionCommand *Cmd : OutputSectionCommands) {
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Flags & SHF_ALLOC)
MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
else
Sec->Addr = 0;
}
- allocateHeaders(Phdrs, *OutputSections, MinVA);
+ allocateHeaders(Phdrs, OutputSectionCommands, MinVA);
}
// Creates program headers as instructed by PHDRS linker script command.
@@ -1068,6 +1076,33 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
llvm_unreachable("unsupported Size argument");
}
+// Compress section contents if this section contains debug info.
+template <class ELFT> void OutputSectionCommand::maybeCompress() {
+ typedef typename ELFT::Chdr Elf_Chdr;
+
+ // Compress only DWARF debug sections.
+ if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) ||
+ !Name.startswith(".debug_"))
+ return;
+
+ // Create a section header.
+ Sec->ZDebugHeader.resize(sizeof(Elf_Chdr));
+ auto *Hdr = reinterpret_cast<Elf_Chdr *>(Sec->ZDebugHeader.data());
+ Hdr->ch_type = ELFCOMPRESS_ZLIB;
+ Hdr->ch_size = Sec->Size;
+ Hdr->ch_addralign = Sec->Alignment;
+
+ // Write section contents to a temporary buffer and compress it.
+ std::vector<uint8_t> Buf(Sec->Size);
+ writeTo<ELFT>(Buf.data());
+ if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData))
+ fatal("compress failed: " + llvm::toString(std::move(E)));
+
+ // Update section headers.
+ Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size();
+ Sec->Flags |= SHF_COMPRESSED;
+}
+
template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
Sec->Loc = Buf;
@@ -1084,7 +1119,12 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) {
return;
// Write leading padding.
- ArrayRef<InputSection *> Sections = Sec->Sections;
+ std::vector<InputSection *> Sections;
+ for (BaseCommand *Cmd : Commands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections)
+ if (IS->Live)
+ Sections.push_back(IS);
uint32_t Filler = getFiller();
if (Filler)
fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler);
@@ -1161,3 +1201,8 @@ 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);
+
+template void OutputSectionCommand::maybeCompress<ELF32LE>();
+template void OutputSectionCommand::maybeCompress<ELF32BE>();
+template void OutputSectionCommand::maybeCompress<ELF64LE>();
+template void OutputSectionCommand::maybeCompress<ELF64BE>();