[ELF] - Reuse Decompressor class.

Intention of change is to get rid of code duplication.
Decompressor was introduced in D28105.

Change allows to get rid of few methods relative to decompression.

Differential revision: https://reviews.llvm.org/D28106

llvm-svn: 291758
This commit is contained in:
George Rimar 2017-01-12 10:53:31 +00:00
parent 569ad73d6b
commit 0d8af3697a
5 changed files with 17 additions and 66 deletions

View File

@ -24,6 +24,7 @@
#include "lld/Driver/Driver.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/Decompressor.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
@ -815,7 +816,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
[](InputSectionBase<ELFT> *S) {
if (!S->Live)
return;
if (S->isCompressed())
if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
S->uncompress();
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
MS->splitIntoPieces();

View File

@ -103,4 +103,10 @@ void elf::fatal(std::error_code EC, const Twine &Prefix) {
fatal(Prefix + ": " + EC.message());
}
void elf::fatal(Error &E, const Twine &Prefix) {
handleAllErrors(std::move(E), [&](llvm::ErrorInfoBase &EI) {
fatal(Prefix + ": " + EI.message());
});
}
} // namespace lld

View File

@ -44,6 +44,7 @@ void error(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(Error &E, const Twine &Prefix);
// check() functions are convenient functions to strip errors
// from error-or-value objects.

View File

@ -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>
@ -128,71 +129,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");
Decompressor Decompressor = check(Decompressor::create(
Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little,
ELFT::Is64Bits));
// 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);
// 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);
}

View File

@ -138,22 +138,12 @@ public:
// section.
uintX_t getOffset(uintX_t Offset) const;
// ELF supports ZLIB-compressed section.
// Returns true if the section is compressed.
bool isCompressed() const;
void uncompress();
// Returns a source location string. Used to construct an error message.
std::string getLocation(uintX_t Offset);
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);
};
// SectionPiece represents a piece of splittable section contents.