Index: lld/trunk/ELF/Config.h
===================================================================
--- lld/trunk/ELF/Config.h
+++ lld/trunk/ELF/Config.h
@@ -104,6 +104,7 @@
bool Bsymbolic;
bool BsymbolicFunctions;
bool ColorDiagnostics = false;
+ bool CompressDebugSections;
bool DefineCommon;
bool Demangle = true;
bool DisableVerify;
Index: lld/trunk/ELF/Driver.cpp
===================================================================
--- lld/trunk/ELF/Driver.cpp
+++ lld/trunk/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,25 @@
return Ret;
}
+static bool getCompressDebugSections(opt::InputArgList &Args) {
+ if (auto *Arg = Args.getLastArg(OPT_compress_debug_sections)) {
+ StringRef S = Arg->getValue();
+ if (S == "none")
+ return false;
+ if (S == "zlib")
+ return zlib::isAvailable();
+ 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);
Index: lld/trunk/ELF/Options.td
===================================================================
--- lld/trunk/ELF/Options.td
+++ lld/trunk/ELF/Options.td
@@ -22,6 +22,9 @@
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<"
">,
HelpText<"Add a directory to the library search path">;
Index: lld/trunk/ELF/OutputSections.h
===================================================================
--- lld/trunk/ELF/OutputSections.h
+++ lld/trunk/ELF/OutputSections.h
@@ -84,9 +84,14 @@
uint32_t getFiller();
template void writeTo(uint8_t *Buf);
template void finalize();
+ template void maybeCompress();
void assignOffsets();
std::vector Sections;
+ // Used for implementation of --compress-debug-sections option.
+ llvm::SmallVector CompressedData;
+ std::vector CompressedHeader;
+
// Location in the output buffer.
uint8_t *Loc = nullptr;
};
Index: lld/trunk/ELF/OutputSections.cpp
===================================================================
--- lld/trunk/ELF/OutputSections.cpp
+++ lld/trunk/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,55 @@
return LA->OutSecOff < LB->OutSecOff;
}
+// Compressed sections has header which we create in this function.
+// Format is explaned here:
+// https://docs.oracle.com/cd/E53394_01/html/E54813/section_compression.html
+template
+static std::vector createHeader(size_t Size, uint32_t Alignment) {
+ const endianness E = ELFT::TargetEndianness;
+
+ std::vector Ret(sizeof(typename ELFT::Chdr));
+ uint8_t *Buf = &Ret[0];
+ write32(Buf, ELFCOMPRESS_ZLIB);
+ Buf += 4;
+
+ if (Config->Is64) {
+ Buf += sizeof(Elf64_Word); // Skip ch_reserved field.
+ write64(Buf, Size);
+ Buf += sizeof(ELFT::Chdr::ch_size);
+ write64(Buf, Alignment);
+ Buf += sizeof(ELFT::Chdr::ch_addralign);
+ } else {
+ write32(Buf, Size);
+ Buf += sizeof(ELFT::Chdr::ch_size);
+ write32(Buf, Alignment);
+ Buf += sizeof(ELFT::Chdr::ch_addralign);
+ }
+
+ return Ret;
+}
+
+template void OutputSection::maybeCompress() {
+ // If -compress-debug-sections is specified, we compress output debug
+ // sections.
+ if (!Config->CompressDebugSections || !Name.startswith(".debug_") ||
+ (Flags & SHF_ALLOC))
+ return;
+
+ this->Flags |= SHF_COMPRESSED;
+ CompressedHeader = createHeader(this->Size, this->Alignment);
+
+ // Here we write relocated content of sections and compress it.
+ std::vector Data(this->Size);
+ this->writeTo(&Data[0]);
+
+ if (Error E = zlib::compress(StringRef((char *)Data.data(), Data.size()),
+ CompressedData))
+ fatal("compress failed: " + llvm::toString(std::move(E)));
+
+ this->Size = this->CompressedHeader.size() + this->CompressedData.size();
+}
+
template void OutputSection::finalize() {
if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
@@ -245,6 +295,15 @@
template 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, CompressedHeader.data(), CompressedHeader.size());
+ Buf += CompressedHeader.size();
+ memcpy(Buf, CompressedData.data(), CompressedData.size());
+ return;
+ }
+
// Write leading padding.
uint32_t Filler = getFiller();
if (Filler)
@@ -422,6 +481,11 @@
template void OutputSection::finalize();
template void OutputSection::finalize();
+template void OutputSection::maybeCompress();
+template void OutputSection::maybeCompress();
+template void OutputSection::maybeCompress();
+template void OutputSection::maybeCompress();
+
template void OutputSection::writeTo(uint8_t *Buf);
template void OutputSection::writeTo(uint8_t *Buf);
template void OutputSection::writeTo(uint8_t *Buf);
Index: lld/trunk/ELF/Writer.cpp
===================================================================
--- lld/trunk/ELF/Writer.cpp
+++ lld/trunk/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"
@@ -1216,6 +1217,11 @@
for (OutputSection *Sec : OutputSections)
Sec->finalize();
+ // Some sections may require compression. That happens for
+ // debug sections when --compress-debug-sections option used.
+ parallelForEach(OutputSections.begin(), OutputSections.end(),
+ [](OutputSection *S) { S->maybeCompress(); });
+
// createThunks may have added local symbols to the static symbol table
applySynthetic({In::SymTab, In::ShStrTab, In::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
Index: lld/trunk/test/ELF/compress-debug-output.s
===================================================================
--- lld/trunk/test/ELF/compress-debug-output.s
+++ lld/trunk/test/ELF/compress-debug-output.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# REQUIRES: zlib
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t1 --compress-debug-sections=zlib
+
+# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=ZLIBCONTENT
+# ZLIBCONTENT: Contents of section .debug_str:
+# ZLIBCONTENT-NOT: AAAAAAAAA
+
+# RUN: llvm-readobj -s %t1 | FileCheck %s --check-prefix=ZLIBFLAGS
+# ZLIBFLAGS: Section {
+# ZLIBFLAGS: Index:
+# ZLIBFLAGS: Name: .debug_str
+# ZLIBFLAGS-NEXT: Type: SHT_PROGBITS
+# ZLIBFLAGS-NEXT: Flags [
+# ZLIBFLAGS-NEXT: SHF_COMPRESSED
+
+# RUN: llvm-dwarfdump %t1 -debug-dump=str | \
+# RUN: FileCheck %s --check-prefix=DEBUGSTR
+# DEBUGSTR: .debug_str contents:
+# DEBUGSTR-NEXT: AAAAAAAAAAAAAAAAAAAAAAAAAAA
+# DEBUGSTR-NEXT: BBBBBBBBBBBBBBBBBBBBBBBBBBB
+
+# RUN: not ld.lld %t.o -o %t1 --compress-debug-sections=zlib-gabi 2>&1 | \
+# RUN: FileCheck -check-prefix=ERR %s
+# ERR: unknown --compress-debug-sections value: zlib-gabi
+
+.section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "AAAAAAAAAAAAAAAAAAAAAAAAAAA"
+.Linfo_string1:
+ .asciz "BBBBBBBBBBBBBBBBBBBBBBBBBBB"