Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -127,6 +127,11 @@ void relocate(uint8_t *Buf, uint8_t *BufEnd); std::vector Relocations; + +private: + void maybeUnpackContent(); + + SmallVector Unpacked; }; template InputSectionBase InputSectionBase::Discarded; Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -14,6 +14,7 @@ #include "OutputSections.h" #include "Target.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -25,6 +26,28 @@ using namespace lld::elf; template +void InputSectionBase::maybeUnpackContent() { + const endianness E = ELFT::TargetEndianness; + if (!(Header->sh_flags & SHF_COMPRESSED)) + return; + if (!zlib::isAvailable()) + fatal("build lld with zlib to enable compressed sections support"); + + ArrayRef Data = getSectionData(); + if (read32(Data.data()) != ELFCOMPRESS_ZLIB) + fatal("unsupported elf compression type"); + + size_t UnpackedSize = + read(ELFT::Is64Bits ? (Data.data() + sizeof(Elf64_Word) * 2) + : (Data.data() + sizeof(Elf32_Word))); + + size_t HdrSize = ELFT::Is64Bits ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); + StringRef Buf((const char *)Data.data() + HdrSize, Data.size() - HdrSize); + if (zlib::uncompress(Buf, Unpacked, UnpackedSize) != zlib::StatusOK) + fatal("error uncompressing section"); +} + +template InputSectionBase::InputSectionBase(elf::ObjectFile *File, const Elf_Shdr *Header, Kind SectionKind) @@ -36,6 +59,8 @@ // The ELF spec states that a value of 0 means the section has // no alignment constraits. Align = std::max(Header->sh_addralign, 1); + + maybeUnpackContent(); } template size_t InputSectionBase::getSize() const { @@ -51,6 +76,8 @@ template ArrayRef InputSectionBase::getSectionData() const { + if (!Unpacked.empty()) + return ArrayRef((const uint8_t *)Unpacked.data(), Unpacked.size()); return check(this->File->getObj().getSectionContents(this->Header)); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1192,6 +1192,7 @@ StringRef OutsecName) { const Elf_Shdr *H = C->getSectionHdr(); uintX_t Flags = H->sh_flags & ~SHF_GROUP; + Flags &= ~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 Index: test/ELF/compressed-debug.s =================================================================== --- test/ELF/compressed-debug.s +++ test/ELF/compressed-debug.s @@ -0,0 +1,67 @@ +## zlib support is disabled under windows now (https://llvm.org/bugs/show_bug.cgi?id=19403). +## So this test requires *nix to run. + +# REQUIRES: shell +# REQUIRES: x86 + +## Test uses pre-generated object file. That is because llvm-mc does not support zlib compressed +## sections in not gnu style at this moment. lld does not and probably will not support zlib-gnu +## inputs as them are depricated in binutils. Instruction how to build the object input is below: +## +## Use the following compressed-debug.s file: +## +##.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" +## +## Generate the object, use objcopy tool to compress the debug sections: +## llvm-mc -filetype=obj -triple=x86_64-pc-linux compressed-debug.s -o compressed-debug-tmp.o +## objcopy --compress-debug-sections=zlib compressed-debug-tmp.o compressed-debug.o + +# RUN: llvm-readobj -sections %S/Inputs/compressed-debug.o | FileCheck -check-prefix=PACKED %s +# PACKED: Section { +# PACKED: Index: 2 +# PACKED: Name: .debug_str +# PACKED-NEXT: Type: SHT_PROGBITS +# PACKED-NEXT: Flags [ +# PACKED-NEXT: SHF_MERGE (0x10) +# PACKED-NEXT: SHF_STRINGS (0x20) +# PACKED-NEXT: 0x800 +# PACKED-NEXT: ] +# PACKED-NEXT: Address: 0x0 +# PACKED-NEXT: Offset: 0x40 +# PACKED-NEXT: Size: 66 +# PACKED-NEXT: Link: 0 +# PACKED-NEXT: Info: 0 +# PACKED-NEXT: AddressAlignment: 1 +# PACKED-NEXT: EntrySize: 1 +# PACKED-NEXT: } + +# RUN: ld.lld %S/Inputs/compressed-debug.o -o %t.so -shared +# RUN: llvm-readobj -sections %t.so | FileCheck -check-prefix=UNPACKED %s + +## Check that section is decompressed and compression flag is removed. +# UNPACKED: Section { +# UNPACKED: Index: 6 +# UNPACKED: Name: .debug_str +# UNPACKED-NEXT: Type: SHT_PROGBITS +# UNPACKED-NEXT: Flags [ +# UNPACKED-NEXT: SHF_MERGE (0x10) +# UNPACKED-NEXT: SHF_STRINGS (0x20) +# UNPACKED-NEXT: ] +# UNPACKED-NEXT: Address: 0x0 +# UNPACKED-NEXT: Offset: 0x1060 +# UNPACKED-NEXT: Size: 69 +# UNPACKED-NEXT: Link: 0 +# UNPACKED-NEXT: Info: 0 +# UNPACKED-NEXT: AddressAlignment: 1 +# UNPACKED-NEXT: EntrySize: 1 +# UNPACKED-NEXT: }