diff options
Diffstat (limited to 'ELF/InputSection.cpp')
-rw-r--r-- | ELF/InputSection.cpp | 73 |
1 files changed, 12 insertions, 61 deletions
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index e87d92aa207c..358004248373 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -19,6 +19,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "llvm/Object/Decompressor.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include <mutex> @@ -35,7 +36,10 @@ using namespace lld::elf; // Returns a string to construct an error message. template <class ELFT> std::string lld::toString(const InputSectionBase<ELFT> *Sec) { - return (Sec->getFile()->getName() + ":(" + Sec->Name + ")").str(); + // File can be absent if section is synthetic. + std::string FileName = + Sec->getFile() ? Sec->getFile()->getName() : "<internal>"; + return (FileName + ":(" + Sec->Name + ")").str(); } template <class ELFT> @@ -102,11 +106,6 @@ template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const { return Data.size(); } -// Returns a string for an error message. -template <class SectionT> static std::string getName(SectionT *Sec) { - return (Sec->getFile()->getName() + ":(" + Sec->Name + ")").str(); -} - template <class ELFT> typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { switch (kind()) { @@ -128,71 +127,23 @@ typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const { llvm_unreachable("invalid section kind"); } -template <class ELFT> bool InputSectionBase<ELFT>::isCompressed() const { - return (Flags & SHF_COMPRESSED) || Name.startswith(".zdebug"); -} - -// 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(toString(this) + ": corrupted compressed section"); - auto *Hdr = reinterpret_cast<const Elf_Chdr *>(Data.data()); - if (Hdr->ch_type != ELFCOMPRESS_ZLIB) - fatal(toString(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(toString(this) + ": corrupted compressed section"); - auto *Hdr = reinterpret_cast<const ZlibHeader *>(Data.data()); - if (memcmp(Hdr->Magic, "ZLIB", 4)) - fatal(toString(this) + ": broken ZLIB-compressed section"); - return {Data.slice(sizeof(*Hdr)), read64be(Hdr->Size)}; -} - // Uncompress section contents. Note that this function is called // from parallel_for_each, so it must be thread-safe. template <class ELFT> void InputSectionBase<ELFT>::uncompress() { - if (!zlib::isAvailable()) - fatal(toString(this) + - ": build lld with zlib to enable compressed sections support"); - - // 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 (Flags & SHF_COMPRESSED) - std::tie(Buf, Size) = getElfCompressedData(Data); - else - std::tie(Buf, Size) = getRawCompressedData(Data); + Decompressor Decompressor = check(Decompressor::create( + Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little, + ELFT::Is64Bits)); - // Uncompress Buf. + size_t Size = Decompressor.getDecompressedSize(); char *OutputBuf; { static std::mutex Mu; std::lock_guard<std::mutex> Lock(Mu); OutputBuf = BAlloc.Allocate<char>(Size); } - if (zlib::uncompress(toStringRef(Buf), OutputBuf, Size) != zlib::StatusOK) - fatal(toString(this) + ": error while uncompressing section"); + + if (Error E = Decompressor.decompress({OutputBuf, Size})) + fatal(E, toString(this)); Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); } |