[lld] r284068 - Support GNU-style ZLIB-compressed input sections.

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 17 09:57:20 PDT 2016


Awesome - thanks!

On Wed, Oct 12, 2016 at 3:45 PM Rui Ueyama via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: ruiu
> Date: Wed Oct 12 17:36:31 2016
> New Revision: 284068
>
> URL: http://llvm.org/viewvc/llvm-project?rev=284068&view=rev
> Log:
> Support GNU-style ZLIB-compressed input sections.
>
> Previously, we supported only SHF_COMPRESSED sections because it's
> new and it's the ELF standard. But there are object files compressed
> in the GNU style out there, so we had to support it.
>
> Sections compressed in the GNU style start with ".zdebug_" and
> contain different headers than the ELF standard's one. In this
> patch, getRawCompressedData is responsible to handle it.
>
> A tricky thing about GNU-style compressed sections is that we have
> to rename them when creating output sections. ".zdebug_" prefix
> implies the section is compressed. We need to rename ".zdebug_"
> ".debug" because our output sections are not compressed.
> We do that in this patch.
>
> Modified:
>     lld/trunk/ELF/InputSection.cpp
>     lld/trunk/ELF/InputSection.h
>     lld/trunk/ELF/LinkerScript.cpp
>     lld/trunk/ELF/Writer.cpp
>     lld/trunk/ELF/Writer.h
>     lld/trunk/test/ELF/compressed-debug-input.s
>
> Modified: lld/trunk/ELF/InputSection.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=284068&r1=284067&r2=284068&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/InputSection.cpp (original)
> +++ lld/trunk/ELF/InputSection.cpp Wed Oct 12 17:36:31 2016
> @@ -23,6 +23,7 @@
>  using namespace llvm;
>  using namespace llvm::ELF;
>  using namespace llvm::object;
> +using namespace llvm::support;
>  using namespace llvm::support::endian;
>
>  using namespace lld;
> @@ -40,12 +41,19 @@ static ArrayRef<uint8_t> getSectionConte
>    return check(File->getObj().getSectionContents(Hdr));
>  }
>
> +// ELF supports ZLIB-compressed section. Returns true if the section
> +// is compressed.
> +template <class ELFT>
> +static bool isCompressed(const typename ELFT::Shdr *Hdr, StringRef Name) {
> +  return (Hdr->sh_flags & SHF_COMPRESSED) || Name.startswith(".zdebug");
> +}
> +
>  template <class ELFT>
>  InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
>                                           const Elf_Shdr *Hdr, StringRef
> Name,
>                                           Kind SectionKind)
>      : InputSectionData(SectionKind, Name, getSectionContents(File, Hdr),
> -                       Hdr->sh_flags & SHF_COMPRESSED,
> !Config->GcSections),
> +                       isCompressed<ELFT>(Hdr, Name),
> !Config->GcSections),
>        Header(Hdr), File(File), Repl(this) {
>    // The ELF spec states that a value of 0 means the section has
>    // no alignment constraits.
> @@ -100,30 +108,62 @@ typename ELFT::uint InputSectionBase<ELF
>    llvm_unreachable("invalid section kind");
>  }
>
> -template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
> -  if (!zlib::isAvailable())
> -    fatal(getName(this) +
> -          ": build lld with zlib to enable compressed sections support");
> -
> -  // A compressed section consists of a header of Elf_Chdr type
> -  // followed by compressed data.
> +// Returns compressed data and its size when uncompressed.
> +template <class ELFT>
> +std::pair<ArrayRef<uint8_t>, uint64_t>
> +InputSectionBase<ELFT>::getElfCompressedData(ArrayRef<uint8_t> Data) {
> +  // Compressed section with Elf_Chdr is the ELF standard.
>    if (Data.size() < sizeof(Elf_Chdr))
> -    fatal("corrupt compressed section");
> -
> +    fatal(getName(this) + ": corrupted compressed section");
>    auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data());
> -  Data = Data.slice(sizeof(Elf_Chdr));
> -
>    if (Hdr->ch_type != ELFCOMPRESS_ZLIB)
>      fatal(getName(this) + ": unsupported compression type");
> +  return {Data.slice(sizeof(*Hdr)), Hdr->ch_size};
> +}
> +
> +// Returns compressed data and its size when uncompressed.
> +template <class ELFT>
> +std::pair<ArrayRef<uint8_t>, uint64_t>
> +InputSectionBase<ELFT>::getRawCompressedData(ArrayRef<uint8_t> Data) {
> +  // Compressed sections without Elf_Chdr header contain this header
> +  // instead. This is a GNU extension.
> +  struct ZlibHeader {
> +    char magic[4]; // should be "ZLIB"
> +    char Size[8];  // Uncompressed size in big-endian
> +  };
> +
> +  if (Data.size() < sizeof(ZlibHeader))
> +    fatal(getName(this) + ": corrupted compressed section");
> +  auto *Hdr = reinterpret_cast<const ZlibHeader *>(Data.data());
> +  if (memcmp(Hdr->magic, "ZLIB", 4))
> +    fatal(getName(this) + ": broken ZLIB-compressed section");
> +  return {Data.slice(sizeof(*Hdr)), read64be(Hdr->Size)};
> +}
> +
> +template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
> +  if (!zlib::isAvailable())
> +    fatal(getName(this) +
> +          ": build lld with zlib to enable compressed sections support");
>
> -  StringRef Buf((const char *)Data.data(), Data.size());
> -  size_t UncompressedDataSize = Hdr->ch_size;
> -  UncompressedData.reset(new char[UncompressedDataSize]);
> -  if (zlib::uncompress(Buf, UncompressedData.get(), UncompressedDataSize)
> !=
> -      zlib::StatusOK)
> -    fatal(getName(this) + ": error uncompressing section");
> -  Data = ArrayRef<uint8_t>((uint8_t *)UncompressedData.get(),
> -                           UncompressedDataSize);
> +  // This section is compressed. Here we decompress it. Ideally, all
> +  // compressed sections have SHF_COMPRESSED bit and their contents
> +  // start with headers of Elf_Chdr type. However, sections whose
> +  // names start with ".zdebug_" don't have the bit and contains a raw
> +  // ZLIB-compressed data (which is a bad thing because section names
> +  // shouldn't be significant in ELF.) We need to be able to read both.
> +  ArrayRef<uint8_t> Buf; // Compressed data
> +  size_t Size;           // Uncompressed size
> +  if (Header->sh_flags & SHF_COMPRESSED)
> +    std::tie(Buf, Size) = getElfCompressedData(Data);
> +  else
> +    std::tie(Buf, Size) = getRawCompressedData(Data);
> +
> +  // Uncompress Buf.
> +  UncompressedData.reset(new uint8_t[Size]);
> +  if (zlib::uncompress(StringRef((const char *)Buf.data(), Buf.size()),
> +                       (char *)UncompressedData.get(), Size) !=
> zlib::StatusOK)
> +    fatal(getName(this) + ": error while uncompressing section");
> +  Data = ArrayRef<uint8_t>(UncompressedData.get(), Size);
>  }
>
>  template <class ELFT>
>
> Modified: lld/trunk/ELF/InputSection.h
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=284068&r1=284067&r2=284068&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/InputSection.h (original)
> +++ lld/trunk/ELF/InputSection.h Wed Oct 12 17:36:31 2016
> @@ -67,7 +67,7 @@ public:
>    ArrayRef<uint8_t> getData(const SectionPiece &P) const;
>
>    // If a section is compressed, this has the uncompressed section data.
> -  std::unique_ptr<char[]> UncompressedData;
> +  std::unique_ptr<uint8_t[]> UncompressedData;
>
>    std::vector<Relocation> Relocations;
>  };
> @@ -118,6 +118,13 @@ public:
>    void uncompress();
>
>    void relocate(uint8_t *Buf, uint8_t *BufEnd);
> +
> +private:
> +  std::pair<ArrayRef<uint8_t>, uint64_t>
> +  getElfCompressedData(ArrayRef<uint8_t> Data);
> +
> +  std::pair<ArrayRef<uint8_t>, uint64_t>
> +  getRawCompressedData(ArrayRef<uint8_t> Data);
>  };
>
>  template <class ELFT> InputSectionBase<ELFT>
> InputSectionBase<ELFT>::Discarded;
>
> Modified: lld/trunk/ELF/LinkerScript.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=284068&r1=284067&r2=284068&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/LinkerScript.cpp (original)
> +++ lld/trunk/ELF/LinkerScript.cpp Wed Oct 12 17:36:31 2016
> @@ -351,7 +351,7 @@ void LinkerScript<ELFT>::createSections(
>    for (ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles())
>      for (InputSectionBase<ELFT> *S : F->getSections())
>        if (!isDiscarded(S) && !S->OutSec)
> -        addSection(Factory, S, getOutputSectionName(S->Name));
> +        addSection(Factory, S, getOutputSectionName(S->Name, Opt.Alloc));
>  }
>
>  // Sets value of a section-defined symbol. Two kinds of
>
> Modified: lld/trunk/ELF/Writer.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=284068&r1=284067&r2=284068&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Writer.cpp (original)
> +++ lld/trunk/ELF/Writer.cpp Wed Oct 12 17:36:31 2016
> @@ -91,7 +91,7 @@ private:
>  };
>  } // anonymous namespace
>
> -StringRef elf::getOutputSectionName(StringRef Name) {
> +StringRef elf::getOutputSectionName(StringRef Name, BumpPtrAllocator
> &Alloc) {
>    if (Config->Relocatable)
>      return Name;
>
> @@ -103,6 +103,11 @@ StringRef elf::getOutputSectionName(Stri
>      if (Name.startswith(V) || Name == Prefix)
>        return Prefix;
>    }
> +
> +  // ".zdebug_" is a prefix for ZLIB-compressed sections.
> +  // Because we decompressed input sections, we want to remove 'z'.
> +  if (Name.startswith(".zdebug_"))
> +    return StringSaver(Alloc).save(Twine(".") + Name.substr(2));
>    return Name;
>  }
>
> @@ -699,7 +704,8 @@ template <class ELFT> void Writer<ELFT>:
>        }
>        OutputSectionBase<ELFT> *Sec;
>        bool IsNew;
> -      std::tie(Sec, IsNew) = Factory.create(IS,
> getOutputSectionName(IS->Name));
> +      StringRef OutsecName = getOutputSectionName(IS->Name, Alloc);
> +      std::tie(Sec, IsNew) = Factory.create(IS, OutsecName);
>        if (IsNew)
>          OutputSections.push_back(Sec);
>        Sec->addSection(IS);
>
> Modified: lld/trunk/ELF/Writer.h
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.h?rev=284068&r1=284067&r2=284068&view=diff
>
> ==============================================================================
> --- lld/trunk/ELF/Writer.h (original)
> +++ lld/trunk/ELF/Writer.h Wed Oct 12 17:36:31 2016
> @@ -10,13 +10,11 @@
>  #ifndef LLD_ELF_WRITER_H
>  #define LLD_ELF_WRITER_H
>
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/Allocator.h"
>  #include <cstdint>
>  #include <memory>
>
> -namespace llvm {
> -  class StringRef;
> -}
> -
>  namespace lld {
>  namespace elf {
>  template <class ELFT> class OutputSectionBase;
> @@ -41,7 +39,8 @@ struct PhdrEntry {
>    bool HasLMA = false;
>  };
>
> -llvm::StringRef getOutputSectionName(llvm::StringRef Name);
> +llvm::StringRef getOutputSectionName(llvm::StringRef Name,
> +                                     llvm::BumpPtrAllocator &Alloc);
>
>  template <class ELFT> void reportDiscarded(InputSectionBase<ELFT> *IS);
>
>
> Modified: lld/trunk/test/ELF/compressed-debug-input.s
> URL:
> http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/compressed-debug-input.s?rev=284068&r1=284067&r2=284068&view=diff
>
> ==============================================================================
> --- lld/trunk/test/ELF/compressed-debug-input.s (original)
> +++ lld/trunk/test/ELF/compressed-debug-input.s Wed Oct 12 17:36:31 2016
> @@ -1,52 +1,73 @@
>  # 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
> +# RUN: llvm-readobj -sections %t | FileCheck -check-prefix=ZLIB %s
> +# ZLIB:      Section {
> +# ZLIB:        Index: 2
> +# ZLIB:        Name: .debug_str
> +# ZLIB-NEXT:   Type: SHT_PROGBITS
> +# ZLIB-NEXT:   Flags [
> +# ZLIB-NEXT:     SHF_COMPRESSED (0x800)
> +# ZLIB-NEXT:     SHF_MERGE (0x10)
> +# ZLIB-NEXT:     SHF_STRINGS (0x20)
> +# ZLIB-NEXT:   ]
> +# ZLIB-NEXT:   Address:
> +# ZLIB-NEXT:   Offset:
> +# ZLIB-NEXT:   Size:
> +# ZLIB-NEXT:   Link:
> +# ZLIB-NEXT:   Info:
> +# ZLIB-NEXT:   AddressAlignment: 1
> +# ZLIB-NEXT:   EntrySize: 1
> +# ZLIB-NEXT: }
>
> -# 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: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj
> -triple=x86_64-unknown-linux %s -o %t2
> +# RUN: llvm-readobj -sections %t2 | FileCheck -check-prefix=GNU %s
> +# GNU:      Section {
> +# GNU:        Index: 2
> +# GNU:        Name: .zdebug_str
> +# GNU-NEXT:   Type: SHT_PROGBITS
> +# GNU-NEXT:   Flags [
> +# GNU-NEXT:     SHF_MERGE (0x10)
> +# GNU-NEXT:     SHF_STRINGS (0x20)
> +# GNU-NEXT:   ]
> +# GNU-NEXT:   Address:
> +# GNU-NEXT:   Offset:
> +# GNU-NEXT:   Size:
> +# GNU-NEXT:   Link:
> +# GNU-NEXT:   Info:
> +# GNU-NEXT:   AddressAlignment: 1
> +# GNU-NEXT:   EntrySize: 1
> +# GNU-NEXT: }
>
>  # RUN: ld.lld %t -o %t.so -shared
> -# RUN: llvm-readobj -sections -section-data %t.so | FileCheck
> -check-prefix=UNCOMPRESSED %s
> +# RUN: llvm-readobj -sections -section-data %t.so | FileCheck
> -check-prefix=DATA %s
>
> -# 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:   SectionData (
> -# UNCOMPRESSED-NEXT:     0000: 73686F72 7420756E 7369676E 65642069
> |short unsigned i|
> -# UNCOMPRESSED-NEXT:     0010: 6E740075 6E736967 6E656420 696E7400
> |nt.unsigned int.|
> -# UNCOMPRESSED-NEXT:     0020: 6C6F6E67 20756E73 69676E65 6420696E  |long
> unsigned in|
> -# UNCOMPRESSED-NEXT:     0030: 74006368 61720075 6E736967 6E656420
> |t.char.unsigned |
> -# UNCOMPRESSED-NEXT:     0040: 63686172 00
> |char.|
> -# UNCOMPRESSED-NEXT:   )
> -# UNCOMPRESSED-NEXT: }
> +# RUN: ld.lld %t2 -o %t2.so -shared
> +# RUN: llvm-readobj -sections -section-data %t2.so | FileCheck
> -check-prefix=DATA %s
> +
> +# DATA:      Section {
> +# DATA:        Index: 6
> +# DATA:        Name: .debug_str
> +# DATA-NEXT:   Type: SHT_PROGBITS
> +# DATA-NEXT:   Flags [
> +# DATA-NEXT:     SHF_MERGE (0x10)
> +# DATA-NEXT:     SHF_STRINGS (0x20)
> +# DATA-NEXT:   ]
> +# DATA-NEXT:   Address: 0x0
> +# DATA-NEXT:   Offset: 0x1060
> +# DATA-NEXT:   Size: 69
> +# DATA-NEXT:   Link: 0
> +# DATA-NEXT:   Info: 0
> +# DATA-NEXT:   AddressAlignment: 1
> +# DATA-NEXT:   EntrySize: 1
> +# DATA-NEXT:   SectionData (
> +# DATA-NEXT:     0000: 73686F72 7420756E 7369676E 65642069  |short
> unsigned i|
> +# DATA-NEXT:     0010: 6E740075 6E736967 6E656420 696E7400  |nt.unsigned
> int.|
> +# DATA-NEXT:     0020: 6C6F6E67 20756E73 69676E65 6420696E  |long
> unsigned in|
> +# DATA-NEXT:     0030: 74006368 61720075 6E736967 6E656420
> |t.char.unsigned |
> +# DATA-NEXT:     0040: 63686172 00                          |char.|
> +# DATA-NEXT:   )
> +# DATA-NEXT: }
>
>  .section .debug_str,"MS", at progbits,1
>  .LASF2:
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20161017/04ebff39/attachment.html>


More information about the llvm-commits mailing list