diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 36bb7285e52d..abb8efb25f06 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -521,10 +521,14 @@ template void LinkerDriver::link(opt::InputArgList &Args) { // any call of MergeInputSection::getOffset. Do that. for (const std::unique_ptr> &F : Symtab.getObjectFiles()) - for (InputSectionBase *S : F->getSections()) - if (S && S != &InputSection::Discarded && S->Live) - if (auto *MS = dyn_cast>(S)) - MS->splitIntoPieces(); + for (InputSectionBase *S : F->getSections()) { + if (!S || S == &InputSection::Discarded || !S->Live) + continue; + if (S->Compressed) + S->uncompress(); + if (auto *MS = dyn_cast>(S)) + MS->splitIntoPieces(); + } writeResult(&Symtab); } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 35039a4f4965..32fed5504b5e 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -15,6 +15,7 @@ #include "OutputSections.h" #include "Target.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -29,7 +30,8 @@ template InputSectionBase::InputSectionBase(elf::ObjectFile *File, const Elf_Shdr *Header, Kind SectionKind) - : Header(Header), File(File), SectionKind(SectionKind), Repl(this) { + : Header(Header), File(File), SectionKind(SectionKind), Repl(this), + Compressed(Header->sh_flags & SHF_COMPRESSED) { // The garbage collector sets sections' Live bits. // If GC is disabled, all sections are considered live by default. Live = !Config->GcSections; @@ -52,6 +54,9 @@ template StringRef InputSectionBase::getSectionName() const { template ArrayRef InputSectionBase::getSectionData() const { + if (Compressed) + return ArrayRef((const uint8_t *)Uncompressed.data(), + Uncompressed.size()); return check(this->File->getObj().getSectionContents(this->Header)); } @@ -78,6 +83,27 @@ typename ELFT::uint InputSectionBase::getOffset(uintX_t Offset) const { llvm_unreachable("invalid section kind"); } +template void InputSectionBase::uncompress() { + typedef typename std::conditional::type Elf_Chdr; + const endianness E = ELFT::TargetEndianness; + + if (!zlib::isAvailable()) + fatal("build lld with zlib to enable compressed sections support"); + + ArrayRef Data = + check(this->File->getObj().getSectionContents(this->Header)); + if (read32(Data.data()) != ELFCOMPRESS_ZLIB) + fatal("unsupported elf compression type"); + + size_t UncompressedSize = + reinterpret_cast(Data.data())->ch_size; + size_t HdrSize = sizeof(Elf_Chdr); + StringRef Buf((const char *)Data.data() + HdrSize, Data.size() - HdrSize); + if (zlib::uncompress(Buf, Uncompressed, UncompressedSize) != zlib::StatusOK) + fatal("error uncompressing section"); +} + template typename ELFT::uint InputSectionBase::getOffset(const DefinedRegular &Sym) const { diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 38850a1f1cc4..f9ea1bb6e88b 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -41,6 +41,9 @@ protected: // The file this section is from. ObjectFile *File; + // If a section is compressed, this vector has uncompressed section data. + SmallVector Uncompressed; + public: enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; Kind SectionKind; @@ -78,8 +81,12 @@ public: ArrayRef getSectionData() const; + void uncompress(); + void relocate(uint8_t *Buf, uint8_t *BufEnd); std::vector> Relocations; + + bool Compressed; }; template InputSectionBase InputSectionBase::Discarded; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 98752699b6b7..6a40164b5af9 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -623,7 +623,7 @@ SectionKey OutputSectionFactory::createKey(InputSectionBase *C, StringRef OutsecName) { const Elf_Shdr *H = C->getSectionHdr(); - uintX_t Flags = H->sh_flags & ~SHF_GROUP; + uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; // For SHF_MERGE we create different output sections for each alignment. // This makes each output section simple and keeps a single level mapping from diff --git a/lld/test/ELF/compressed-debug-input.s b/lld/test/ELF/compressed-debug-input.s new file mode 100644 index 000000000000..5d0471bf15ec --- /dev/null +++ b/lld/test/ELF/compressed-debug-input.s @@ -0,0 +1,55 @@ +# REQUIRES: zlib + +# RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=COMPRESSED %s + +# COMPRESSED: Section { +# COMPRESSED: Index: 2 +# COMPRESSED: Name: .debug_str +# COMPRESSED-NEXT: Type: SHT_PROGBITS +# COMPRESSED-NEXT: Flags [ +# COMPRESSED-NEXT: SHF_COMPRESSED (0x800) +# COMPRESSED-NEXT: SHF_MERGE (0x10) +# COMPRESSED-NEXT: SHF_STRINGS (0x20) +# COMPRESSED-NEXT: ] +# COMPRESSED-NEXT: Address: +# COMPRESSED-NEXT: Offset: +# COMPRESSED-NEXT: Size: 66 +# COMPRESSED-NEXT: Link: +# COMPRESSED-NEXT: Info: +# COMPRESSED-NEXT: AddressAlignment: 1 +# COMPRESSED-NEXT: EntrySize: 1 +# COMPRESSED-NEXT: } + +# RUN: ld.lld %t -o %t.so -shared +# RUN: llvm-readobj -sections %t.so | FileCheck -check-prefix=UNCOMPRESSED %s + +## Check that section is decompressed and compression flag is removed. +# UNCOMPRESSED: Section { +# UNCOMPRESSED: Index: 6 +# UNCOMPRESSED: Name: .debug_str +# UNCOMPRESSED-NEXT: Type: SHT_PROGBITS +# UNCOMPRESSED-NEXT: Flags [ +# UNCOMPRESSED-NEXT: SHF_MERGE (0x10) +# UNCOMPRESSED-NEXT: SHF_STRINGS (0x20) +# UNCOMPRESSED-NEXT: ] +# UNCOMPRESSED-NEXT: Address: 0x0 +# UNCOMPRESSED-NEXT: Offset: 0x1060 +# UNCOMPRESSED-NEXT: Size: 69 +# UNCOMPRESSED-NEXT: Link: 0 +# UNCOMPRESSED-NEXT: Info: 0 +# UNCOMPRESSED-NEXT: AddressAlignment: 1 +# UNCOMPRESSED-NEXT: EntrySize: 1 +# UNCOMPRESSED-NEXT: } + +.section .debug_str,"MS",@progbits,1 +.LASF2: + .string "short unsigned int" +.LASF3: + .string "unsigned int" +.LASF0: + .string "long unsigned int" +.LASF8: + .string "char" +.LASF1: + .string "unsigned char"