[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

llvm-svn: 273661
This commit is contained in:
George Rimar 2016-06-24 11:18:44 +00:00
parent 998fb5c28b
commit 602fbee9fc
5 changed files with 98 additions and 6 deletions

View File

@ -521,10 +521,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// any call of MergeInputSection::getOffset. Do that. // any call of MergeInputSection::getOffset. Do that.
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
Symtab.getObjectFiles()) Symtab.getObjectFiles())
for (InputSectionBase<ELFT> *S : F->getSections()) for (InputSectionBase<ELFT> *S : F->getSections()) {
if (S && S != &InputSection<ELFT>::Discarded && S->Live) if (!S || S == &InputSection<ELFT>::Discarded || !S->Live)
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) continue;
MS->splitIntoPieces(); if (S->Compressed)
S->uncompress();
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
MS->splitIntoPieces();
}
writeResult<ELFT>(&Symtab); writeResult<ELFT>(&Symtab);
} }

View File

@ -15,6 +15,7 @@
#include "OutputSections.h" #include "OutputSections.h"
#include "Target.h" #include "Target.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h" #include "llvm/Support/Endian.h"
using namespace llvm; using namespace llvm;
@ -29,7 +30,8 @@ template <class ELFT>
InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File, InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
const Elf_Shdr *Header, const Elf_Shdr *Header,
Kind SectionKind) 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. // The garbage collector sets sections' Live bits.
// If GC is disabled, all sections are considered live by default. // If GC is disabled, all sections are considered live by default.
Live = !Config->GcSections; Live = !Config->GcSections;
@ -52,6 +54,9 @@ template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
template <class ELFT> template <class ELFT>
ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const { 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)); 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"); 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> template <class ELFT>
typename ELFT::uint typename ELFT::uint
InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const { InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {

View File

@ -41,6 +41,9 @@ protected:
// The file this section is from. // The file this section is from.
ObjectFile<ELFT> *File; ObjectFile<ELFT> *File;
// If a section is compressed, this vector has uncompressed section data.
SmallVector<char, 0> Uncompressed;
public: public:
enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions };
Kind SectionKind; Kind SectionKind;
@ -78,8 +81,12 @@ public:
ArrayRef<uint8_t> getSectionData() const; ArrayRef<uint8_t> getSectionData() const;
void uncompress();
void relocate(uint8_t *Buf, uint8_t *BufEnd); void relocate(uint8_t *Buf, uint8_t *BufEnd);
std::vector<Relocation<ELFT>> Relocations; std::vector<Relocation<ELFT>> Relocations;
bool Compressed;
}; };
template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded; template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;

View File

@ -623,7 +623,7 @@ SectionKey<ELFT::Is64Bits>
OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C, OutputSectionFactory<ELFT>::createKey(InputSectionBase<ELFT> *C,
StringRef OutsecName) { StringRef OutsecName) {
const Elf_Shdr *H = C->getSectionHdr(); 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. // For SHF_MERGE we create different output sections for each alignment.
// This makes each output section simple and keeps a single level mapping from // This makes each output section simple and keeps a single level mapping from

View File

@ -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"