commit c6ebc651b6fac9cf1d9f8c00ea49d29093003f85 Author: Simon Atanasyan Date: Fri Aug 6 13:29:47 2021 +0300 [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 diff --git lld/ELF/InputSection.cpp lld/ELF/InputSection.cpp index 1f9fa961fc2..7d952e9037f 100644 --- lld/ELF/InputSection.cpp +++ lld/ELF/InputSection.cpp @@ -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(); + break; + case ELF32BEKind: + parseCompressedHeader(); + break; + case ELF64LEKind: + parseCompressedHeader(); + break; + case ELF64BEKind: + parseCompressedHeader(); + 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 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(rawData.data()); - if (hdr->ch_type != ELFCOMPRESS_ZLIB) { - error(toString(this) + ": unsupported compression type"); - return; - } - - uncompressedSize = hdr->ch_size; - alignment = std::max(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(rawData.data()); + auto *hdr = reinterpret_cast(rawData.data()); if (hdr->ch_type != ELFCOMPRESS_ZLIB) { error(toString(this) + ": unsupported compression type"); return; diff --git lld/ELF/InputSection.h lld/ELF/InputSection.h index 5b91c1c90bd..c914d0b4215 100644 --- lld/ELF/InputSection.h +++ lld/ELF/InputSection.h @@ -238,6 +238,7 @@ public: } protected: + template void parseCompressedHeader(); void uncompress() const; diff --git lld/test/ELF/compressed-debug-input-err.s lld/test/ELF/compressed-debug-input-err.s index 89773eca59d..0495a9eaa08 100644 --- lld/test/ELF/compressed-debug-input-err.s +++ lld/test/ELF/compressed-debug-input-err.s @@ -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 diff --git lld/test/ELF/compressed-debug-input.s lld/test/ELF/compressed-debug-input.s index c9bfd3e5162..5b61ea8b384 100644 --- lld/test/ELF/compressed-debug-input.s +++ lld/test/ELF/compressed-debug-input.s @@ -1,7 +1,9 @@ # 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