diff options
Diffstat (limited to 'lld/ELF/OutputSections.cpp')
-rw-r--r-- | lld/ELF/OutputSections.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 93f83100a74..9fc696921ae 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -16,6 +16,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" @@ -83,6 +84,55 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) { return LA->OutSecOff < LB->OutSecOff; } +// Compressed sections has header which we create in this function. +// Format is explaned here: +// https://docs.oracle.com/cd/E53394_01/html/E54813/section_compression.html +template <class ELFT> +static std::vector<uint8_t> createHeader(size_t Size, uint32_t Alignment) { + const endianness E = ELFT::TargetEndianness; + + std::vector<uint8_t> Ret(sizeof(typename ELFT::Chdr)); + uint8_t *Buf = &Ret[0]; + write32<E>(Buf, ELFCOMPRESS_ZLIB); + Buf += 4; + + if (Config->Is64) { + Buf += sizeof(Elf64_Word); // Skip ch_reserved field. + write64<E>(Buf, Size); + Buf += sizeof(ELFT::Chdr::ch_size); + write64<E>(Buf, Alignment); + Buf += sizeof(ELFT::Chdr::ch_addralign); + } else { + write32<E>(Buf, Size); + Buf += sizeof(ELFT::Chdr::ch_size); + write32<E>(Buf, Alignment); + Buf += sizeof(ELFT::Chdr::ch_addralign); + } + + return Ret; +} + +template <class ELFT> void OutputSection::maybeCompress() { + // If -compress-debug-sections is specified, we compress output debug + // sections. + if (!Config->CompressDebugSections || !Name.startswith(".debug_") || + (Flags & SHF_ALLOC)) + return; + + this->Flags |= SHF_COMPRESSED; + CompressedHeader = createHeader<ELFT>(this->Size, this->Alignment); + + // Here we write relocated content of sections and compress it. + std::vector<uint8_t> Data(this->Size); + this->writeTo<ELFT>(&Data[0]); + + if (Error E = zlib::compress(StringRef((char *)Data.data(), Data.size()), + CompressedData)) + fatal("compress failed: " + llvm::toString(std::move(E))); + + this->Size = this->CompressedHeader.size() + this->CompressedData.size(); +} + template <class ELFT> void OutputSection::finalize() { if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) { std::sort(Sections.begin(), Sections.end(), compareByFilePosition); @@ -245,6 +295,15 @@ uint32_t OutputSection::getFiller() { template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { Loc = Buf; + // We may have already rendered compressed content when using + // -compress-debug-sections option. Write it together with header. + if (!CompressedData.empty()) { + memcpy(Buf, CompressedHeader.data(), CompressedHeader.size()); + Buf += CompressedHeader.size(); + memcpy(Buf, CompressedData.data(), CompressedData.size()); + return; + } + // Write leading padding. uint32_t Filler = getFiller(); if (Filler) @@ -422,6 +481,11 @@ template void OutputSection::finalize<ELF32BE>(); template void OutputSection::finalize<ELF64LE>(); template void OutputSection::finalize<ELF64BE>(); +template void OutputSection::maybeCompress<ELF32LE>(); +template void OutputSection::maybeCompress<ELF32BE>(); +template void OutputSection::maybeCompress<ELF64LE>(); +template void OutputSection::maybeCompress<ELF64BE>(); + template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf); template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf); template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf); |