aboutsummaryrefslogtreecommitdiffstats
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-20 21:21:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-20 21:21:19 +0000
commitbe08ec96063be8c1a1a8621eccd05a4ebeecfb42 (patch)
treea390ff37f3537ba45537f8cd0a0b6c19c9251ca5 /ELF
parentd2d3ebb81992e107edf95c1c136d7a342d9b1418 (diff)
downloadsrc-be08ec96063be8c1a1a8621eccd05a4ebeecfb42.tar.gz
src-be08ec96063be8c1a1a8621eccd05a4ebeecfb42.zip
Vendor import of lld trunk r300890:vendor/lld/lld-trunk-r300890
Notes
Notes: svn path=/vendor/lld/dist/; revision=317226 svn path=/vendor/lld/lld-trunk-r300890/; revision=317227; tag=vendor/lld/lld-trunk-r300890
Diffstat (limited to 'ELF')
-rw-r--r--ELF/Config.h1
-rw-r--r--ELF/Driver.cpp13
-rw-r--r--ELF/LinkerScript.cpp50
-rw-r--r--ELF/LinkerScript.h1
-rw-r--r--ELF/Options.td3
-rw-r--r--ELF/OutputSections.cpp42
-rw-r--r--ELF/OutputSections.h5
-rw-r--r--ELF/Writer.cpp47
8 files changed, 125 insertions, 37 deletions
diff --git a/ELF/Config.h b/ELF/Config.h
index c8eecec7439c..d25c63c3c0d2 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -104,6 +104,7 @@ struct Configuration {
bool Bsymbolic;
bool BsymbolicFunctions;
bool ColorDiagnostics = false;
+ bool CompressDebugSections;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 47ecd607a48f..93924e4554c9 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -45,6 +45,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/Decompressor.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
@@ -564,12 +565,24 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
return Ret;
}
+static bool getCompressDebugSections(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_compress_debug_sections)) {
+ StringRef S = Arg->getValue();
+ if (S == "zlib")
+ return zlib::isAvailable();
+ if (S != "none")
+ error("unknown --compress-debug-sections value: " + S);
+ }
+ return false;
+}
+
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->CompressDebugSections = getCompressDebugSections(Args);
Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
!Args.hasArg(OPT_relocatable));
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index ab2ca22e9e17..63eb90456e17 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -413,6 +413,56 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) {
CurOutSec = nullptr;
}
+void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) {
+ std::vector<BaseCommand *> Commands;
+
+ // Define start address
+ uint64_t StartAddr = Config->ImageBase;
+ if (AllocateHeader)
+ StartAddr += elf::getHeaderSize();
+
+ // The Sections with -T<section> are sorted in order of ascending address
+ // we must use this if it is lower than StartAddr as calls to setDot() must
+ // be monotonically increasing
+ if (!Config->SectionStartMap.empty()) {
+ uint64_t LowestSecStart = Config->SectionStartMap.begin()->second;
+ StartAddr = std::min(StartAddr, LowestSecStart);
+ }
+ Commands.push_back(
+ make<SymbolAssignment>(".", [=] { return StartAddr; }, ""));
+
+ // For each OutputSection that needs a VA fabricate an OutputSectionCommand
+ // with an InputSectionDescription describing the InputSections
+ for (OutputSection *Sec : *OutputSections) {
+ if (!(Sec->Flags & SHF_ALLOC))
+ continue;
+
+ auto I = Config->SectionStartMap.find(Sec->Name);
+ if (I != Config->SectionStartMap.end())
+ Commands.push_back(
+ make<SymbolAssignment>(".", [=] { return I->second; }, ""));
+
+ auto *OSCmd = make<OutputSectionCommand>(Sec->Name);
+ OSCmd->Sec = Sec;
+ if (Sec->PageAlign)
+ OSCmd->AddrExpr = [=] {
+ return alignTo(Script->getDot(), Config->MaxPageSize);
+ };
+ Commands.push_back(OSCmd);
+ if (Sec->Sections.size()) {
+ auto *ISD = make<InputSectionDescription>("");
+ OSCmd->Commands.push_back(ISD);
+ for (InputSection *ISec : Sec->Sections) {
+ ISD->Sections.push_back(ISec);
+ ISec->Assigned = true;
+ }
+ }
+ }
+ // SECTIONS commands run before other non SECTIONS commands
+ Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end());
+ Opt.Commands = std::move(Commands);
+}
+
// Add sections that didn't match any sections command.
void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
for (InputSectionBase *S : InputSections)
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 04a388efb4e9..61942b2db357 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -256,6 +256,7 @@ public:
bool isDefined(StringRef S);
std::vector<OutputSection *> *OutputSections;
+ void fabricateDefaultCommands(bool AllocateHeader);
void addOrphanSections(OutputSectionFactory &Factory);
void removeEmptyCommands();
void adjustSectionsBeforeSorting();
diff --git a/ELF/Options.td b/ELF/Options.td
index 7ed8dfb090bd..4cf14c9011c3 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -22,6 +22,9 @@ def build_id: F<"build-id">, HelpText<"Generate build ID note">;
def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">;
+def compress_debug_sections : J<"compress-debug-sections=">,
+ HelpText<"Compress DWARF debug sections">;
+
def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
HelpText<"Add a directory to the library search path">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 93f83100a745..a40818d2d301 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -16,6 +16,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Threads.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
@@ -83,6 +84,33 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) {
return LA->OutSecOff < LB->OutSecOff;
}
+// Compress section contents if this section contains debug info.
+template <class ELFT> void OutputSection::maybeCompress() {
+ typedef typename ELFT::Chdr Elf_Chdr;
+
+ // Compress only DWARF debug sections.
+ if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) ||
+ !Name.startswith(".debug_"))
+ return;
+
+ // Create a section header.
+ ZDebugHeader.resize(sizeof(Elf_Chdr));
+ auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data());
+ Hdr->ch_type = ELFCOMPRESS_ZLIB;
+ Hdr->ch_size = Size;
+ Hdr->ch_addralign = Alignment;
+
+ // Write section contents to a temporary buffer and compress it.
+ std::vector<uint8_t> Buf(Size);
+ writeTo<ELFT>(Buf.data());
+ if (Error E = zlib::compress(toStringRef(Buf), CompressedData))
+ fatal("compress failed: " + llvm::toString(std::move(E)));
+
+ // Update section headers.
+ Size = sizeof(Elf_Chdr) + CompressedData.size();
+ Flags |= SHF_COMPRESSED;
+}
+
template <class ELFT> void OutputSection::finalize() {
if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
@@ -245,6 +273,15 @@ uint32_t OutputSection::getFiller() {
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)
@@ -422,6 +459,11 @@ template void OutputSection::finalize<ELF32BE>();
template void OutputSection::finalize<ELF64LE>();
template void OutputSection::finalize<ELF64BE>();
+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);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 0ae3df5f7859..bcda77d1a26d 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -84,9 +84,14 @@ public:
uint32_t getFiller();
template <class ELFT> void writeTo(uint8_t *Buf);
template <class ELFT> void finalize();
+ template <class ELFT> void maybeCompress();
void assignOffsets();
std::vector<InputSection *> Sections;
+ // Used for implementation of --compress-debug-sections option.
+ std::vector<uint8_t> ZDebugHeader;
+ llvm::SmallVector<char, 1> CompressedData;
+
// Location in the output buffer.
uint8_t *Loc = nullptr;
};
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 3ded0c675b80..e8718c258c77 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -19,6 +19,7 @@
#include "SymbolTable.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "Threads.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileOutputBuffer.h"
@@ -58,7 +59,6 @@ private:
std::vector<PhdrEntry> createPhdrs();
void removeEmptyPTLoad();
void addPtArmExid(std::vector<PhdrEntry> &Phdrs);
- void assignAddresses();
void assignFileOffsets();
void assignFileOffsetsBinary();
void setPhdrs();
@@ -250,13 +250,11 @@ template <class ELFT> void Writer<ELFT>::run() {
if (Config->Relocatable) {
assignFileOffsets();
} else {
- if (Script->Opt.HasSections) {
- Script->assignAddresses(Phdrs);
- } else {
+ if (!Script->Opt.HasSections) {
fixSectionAlignments();
- assignAddresses();
- Script->processNonSectionCommands();
+ Script->fabricateDefaultCommands(Config->MaxPageSize);
}
+ Script->assignAddresses(Phdrs);
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
// 0 sized region. This has to be done late since only after assignAddresses
@@ -1216,6 +1214,12 @@ 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({In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
@@ -1502,37 +1506,6 @@ template <class ELFT> void Writer<ELFT>::fixHeaders() {
AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min);
}
-// Assign VAs (addresses at run-time) to output sections.
-template <class ELFT> void Writer<ELFT>::assignAddresses() {
- uint64_t VA = Config->ImageBase;
- uint64_t ThreadBssOffset = 0;
-
- if (AllocateHeader)
- VA += getHeaderSize();
-
- for (OutputSection *Sec : OutputSections) {
- uint32_t Alignment = Sec->Alignment;
- if (Sec->PageAlign)
- Alignment = std::max<uint32_t>(Alignment, Config->MaxPageSize);
-
- auto I = Config->SectionStartMap.find(Sec->Name);
- if (I != Config->SectionStartMap.end())
- VA = I->second;
-
- // We only assign VAs to allocated sections.
- if (needsPtLoad(Sec)) {
- VA = alignTo(VA, Alignment);
- Sec->Addr = VA;
- VA += Sec->Size;
- } else if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) {
- uint64_t TVA = VA + ThreadBssOffset;
- TVA = alignTo(TVA, Alignment);
- Sec->Addr = TVA;
- ThreadBssOffset = TVA - VA + Sec->Size;
- }
- }
-}
-
// Adjusts the file alignment for a given output section and returns
// its new file offset. The file offset must be the same with its
// virtual address (modulo the page size) so that the loader can load