Commit c6ebc651 authored by Simon Atanasyan's avatar Simon Atanasyan
Browse files

[LLD] Support compressed input sections on big-endian targets

This patch enables compressed input sections on big-endian targets by
checking the target endianness and selecting an appropriate `Chdr`
structure.

Fixes PR51369

Differential Revision: https://reviews.llvm.org/D107635
parent 4c2e0123
Loading
Loading
Loading
Loading
+20 −27
Original line number Diff line number Diff line
@@ -88,7 +88,22 @@ InputSectionBase::InputSectionBase(InputFile *file, uint64_t flags,
    if (!zlib::isAvailable())
      error(toString(file) + ": contains a compressed section, " +
            "but zlib is not available");
    parseCompressedHeader();
    switch (config->ekind) {
    case ELF32LEKind:
      parseCompressedHeader<ELF32LE>();
      break;
    case ELF32BEKind:
      parseCompressedHeader<ELF32BE>();
      break;
    case ELF64LEKind:
      parseCompressedHeader<ELF64LE>();
      break;
    case ELF64BEKind:
      parseCompressedHeader<ELF64BE>();
      break;
    default:
      llvm_unreachable("unknown ELFT");
    }
  }
}

@@ -210,10 +225,7 @@ OutputSection *SectionBase::getOutputSection() {
// When a section is compressed, `rawData` consists with a header followed
// by zlib-compressed data. This function parses a header to initialize
// `uncompressedSize` member and remove the header from `rawData`.
void InputSectionBase::parseCompressedHeader() {
  using Chdr64 = typename ELF64LE::Chdr;
  using Chdr32 = typename ELF32LE::Chdr;

template <typename ELFT> void InputSectionBase::parseCompressedHeader() {
  // Old-style header
  if (name.startswith(".zdebug")) {
    if (!toStringRef(rawData).startswith("ZLIB")) {
@@ -239,32 +251,13 @@ void InputSectionBase::parseCompressedHeader() {
  assert(flags & SHF_COMPRESSED);
  flags &= ~(uint64_t)SHF_COMPRESSED;

  // New-style 64-bit header
  if (config->is64) {
    if (rawData.size() < sizeof(Chdr64)) {
      error(toString(this) + ": corrupted compressed section");
      return;
    }

    auto *hdr = reinterpret_cast<const Chdr64 *>(rawData.data());
    if (hdr->ch_type != ELFCOMPRESS_ZLIB) {
      error(toString(this) + ": unsupported compression type");
      return;
    }

    uncompressedSize = hdr->ch_size;
    alignment = std::max<uint32_t>(hdr->ch_addralign, 1);
    rawData = rawData.slice(sizeof(*hdr));
    return;
  }

  // New-style 32-bit header
  if (rawData.size() < sizeof(Chdr32)) {
  // New-style header
  if (rawData.size() < sizeof(typename ELFT::Chdr)) {
    error(toString(this) + ": corrupted compressed section");
    return;
  }

  auto *hdr = reinterpret_cast<const Chdr32 *>(rawData.data());
  auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(rawData.data());
  if (hdr->ch_type != ELFCOMPRESS_ZLIB) {
    error(toString(this) + ": unsupported compression type");
    return;
+1 −0
Original line number Diff line number Diff line
@@ -238,6 +238,7 @@ public:
  }

protected:
  template <typename ELFT>
  void parseCompressedHeader();
  void uncompress() const;

+3 −0
Original line number Diff line number Diff line
@@ -3,6 +3,9 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s

# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-unknown %s -o %t-be.o
# RUN: not ld.lld %t-be.o -o /dev/null -shared 2>&1 | FileCheck %s

## Check we are able to report zlib uncompress errors.
# CHECK: error: {{.*}}.o:(.debug_str): uncompress failed: zlib error: Z_DATA_ERROR

+8 −0
Original line number Diff line number Diff line
# REQUIRES: zlib, x86

# RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=powerpc64-unknown-unknown %s -o %t-be
# RUN: llvm-readobj --sections %t | FileCheck -check-prefix=ZLIB %s
# RUN: llvm-readobj --sections %t-be | FileCheck -check-prefix=ZLIB %s
# ZLIB:      Section {
# ZLIB:        Index: 2
# ZLIB:        Name: .debug_str
@@ -21,7 +23,9 @@
# ZLIB-NEXT: }

# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-unknown-linux %s -o %t2
# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=powerpc64-unknown-unknown %s -o %t2-be
# RUN: llvm-readobj --sections %t2 | FileCheck -check-prefix=GNU %s
# RUN: llvm-readobj --sections %t2-be | FileCheck -check-prefix=GNU %s
# GNU:      Section {
# GNU:        Index: 2
# GNU:        Name: .zdebug_str
@@ -41,9 +45,13 @@

# RUN: ld.lld --hash-style=sysv %t -o %t.so -shared
# RUN: llvm-readobj --sections --section-data %t.so | FileCheck -check-prefix=DATA %s
# RUN: ld.lld --hash-style=sysv %t-be -o %t-be.so -shared
# RUN: llvm-readobj --sections --section-data %t-be.so | FileCheck -check-prefix=DATA %s

# RUN: ld.lld --hash-style=sysv %t2 -o %t2.so -shared
# RUN: llvm-readobj --sections --section-data %t2.so | FileCheck -check-prefix=DATA %s
# RUN: ld.lld --hash-style=sysv %t2-be -o %t2-be.so -shared
# RUN: llvm-readobj --sections --section-data %t2-be.so | FileCheck -check-prefix=DATA %s

# DATA:      Section {
# DATA:        Index: 6