diff options
author | George Rimar <grimar@accesssoftek.com> | 2016-06-24 11:18:44 +0000 |
---|---|---|
committer | George Rimar <grimar@accesssoftek.com> | 2016-06-24 11:18:44 +0000 |
commit | 75a1b9762a16df998cd5df4d9d7bc24e85433f41 (patch) | |
tree | 472d44073ace05b690473fbba12d2c7425d322e2 | |
parent | ad716e38c3d0a3dc2d5e0c643c381d2dbe9353bc (diff) |
[ELF] - Support of compressed input sections implemented.
Patch implements support of zlib style compressed sections.
SHF_COMPRESSED flag is used to recognize that decompression is required.
After that decompression is performed and flag is removed from output.
Differential revision: http://reviews.llvm.org/D20272
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@273661 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | ELF/Driver.cpp | 12 | ||||
-rw-r--r-- | ELF/InputSection.cpp | 28 | ||||
-rw-r--r-- | ELF/InputSection.h | 7 | ||||
-rw-r--r-- | ELF/Writer.cpp | 2 | ||||
-rw-r--r-- | test/ELF/compressed-debug-input.s | 55 |
5 files changed, 98 insertions, 6 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 36bb7285e..abb8efb25 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -521,10 +521,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // any call of MergeInputSection::getOffset. Do that. for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) - for (InputSectionBase<ELFT> *S : F->getSections()) - if (S && S != &InputSection<ELFT>::Discarded && S->Live) - if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) - MS->splitIntoPieces(); + for (InputSectionBase<ELFT> *S : F->getSections()) { + if (!S || S == &InputSection<ELFT>::Discarded || !S->Live) + continue; + if (S->Compressed) + S->uncompress(); + if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) + MS->splitIntoPieces(); + } writeResult<ELFT>(&Symtab); } diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 35039a4f4..32fed5504 100644 --- a/ELF/InputSection.cpp +++ b/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 <class ELFT> InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *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 <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const { template <class ELFT> ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const { + if (Compressed) + return ArrayRef<uint8_t>((const uint8_t *)Uncompressed.data(), + Uncompressed.size()); return check(this->File->getObj().getSectionContents(this->Header)); } @@ -78,6 +83,27 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { llvm_unreachable("invalid section kind"); } +template <class ELFT> void InputSectionBase<ELFT>::uncompress() { + typedef typename std::conditional<ELFT::Is64Bits, Elf64_Chdr, + Elf32_Chdr>::type Elf_Chdr; + const endianness E = ELFT::TargetEndianness; + + if (!zlib::isAvailable()) + fatal("build lld with zlib to enable compressed sections support"); + + ArrayRef<uint8_t> Data = + check(this->File->getObj().getSectionContents(this->Header)); + if (read32<E>(Data.data()) != ELFCOMPRESS_ZLIB) + fatal("unsupported elf compression type"); + + size_t UncompressedSize = + reinterpret_cast<const Elf_Chdr *>(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 <class ELFT> typename ELFT::uint InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const { diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 38850a1f1..f9ea1bb6e 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -41,6 +41,9 @@ protected: // The file this section is from. ObjectFile<ELFT> *File; + // If a section is compressed, this vector has uncompressed section data. + SmallVector<char, 0> Uncompressed; + public: enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; Kind SectionKind; @@ -78,8 +81,12 @@ public: ArrayRef<uint8_t> getSectionData() const; + void uncompress(); + void relocate(uint8_t *Buf, uint8_t *BufEnd); std::vector<Relocation<ELFT>> Relocations; + + bool Compressed; }; template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 98752699b..6a40164b5 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -623,7 +623,7 @@ SectionKey<ELFT::Is64Bits> OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *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/test/ELF/compressed-debug-input.s b/test/ELF/compressed-debug-input.s new file mode 100644 index 000000000..5d0471bf1 --- /dev/null +++ b/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" |