aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2016-06-24 11:18:44 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2016-06-24 11:18:44 +0000
commit75a1b9762a16df998cd5df4d9d7bc24e85433f41 (patch)
tree472d44073ace05b690473fbba12d2c7425d322e2
parentad716e38c3d0a3dc2d5e0c643c381d2dbe9353bc (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.cpp12
-rw-r--r--ELF/InputSection.cpp28
-rw-r--r--ELF/InputSection.h7
-rw-r--r--ELF/Writer.cpp2
-rw-r--r--test/ELF/compressed-debug-input.s55
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"