diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -110,6 +110,18 @@ return rawData.size() - bytesDropped; } +template +static void uncompressAux(const InputSectionBase &sec, uint8_t *out, + size_t size) { + auto *hdr = reinterpret_cast(sec.rawData.data()); + auto compressed = sec.rawData.slice(sizeof(typename ELFT::Chdr)); + if (Error e = hdr->ch_type == ELFCOMPRESS_ZLIB + ? compression::zlib::uncompress(compressed, out, size) + : compression::zstd::uncompress(compressed, out, size)) + fatal(toString(&sec) + + ": uncompress failed: " + llvm::toString(std::move(e))); +} + void InputSectionBase::uncompress() const { size_t size = uncompressedSize; uint8_t *uncompressedBuf; @@ -119,9 +131,7 @@ uncompressedBuf = bAlloc().Allocate(size); } - if (Error e = compression::zlib::uncompress(rawData, uncompressedBuf, size)) - fatal(toString(this) + - ": uncompress failed: " + llvm::toString(std::move(e))); + invokeELFT(uncompressAux, *this, uncompressedBuf, size); rawData = makeArrayRef(uncompressedBuf, size); uncompressedSize = -1; } @@ -212,6 +222,10 @@ if (!compression::zlib::isAvailable()) error(toString(this) + " is compressed with ELFCOMPRESS_ZLIB, but lld is " "not built with zlib support"); + } else if (hdr->ch_type == ELFCOMPRESS_ZSTD) { + if (!compression::zstd::isAvailable()) + error(toString(this) + " is compressed with ELFCOMPRESS_ZSTD, but lld is " + "not built with zstd support"); } else { error(toString(this) + ": unsupported compression type (" + Twine(hdr->ch_type) + ")"); @@ -220,7 +234,6 @@ uncompressedSize = hdr->ch_size; alignment = std::max(hdr->ch_addralign, 1); - rawData = rawData.slice(sizeof(*hdr)); } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -1219,8 +1232,12 @@ // If this is a compressed section, uncompress section contents directly // to the buffer. if (uncompressedSize >= 0) { + auto *hdr = reinterpret_cast(rawData.data()); + auto compressed = rawData.slice(sizeof(typename ELFT::Chdr)); size_t size = uncompressedSize; - if (Error e = compression::zlib::uncompress(rawData, buf, size)) + if (Error e = hdr->ch_type == ELFCOMPRESS_ZLIB + ? compression::zlib::uncompress(compressed, buf, size) + : compression::zstd::uncompress(compressed, buf, size)) fatal(toString(this) + ": uncompress failed: " + llvm::toString(std::move(e))); uint8_t *bufEnd = buf + size; diff --git a/lld/test/CMakeLists.txt b/lld/test/CMakeLists.txt --- a/lld/test/CMakeLists.txt +++ b/lld/test/CMakeLists.txt @@ -1,6 +1,7 @@ llvm_canonicalize_cmake_booleans( ENABLE_BACKTRACES LLVM_ENABLE_ZLIB + LLVM_ENABLE_ZSTD LLVM_ENABLE_LIBXML2 LLD_DEFAULT_LD_LLD_IS_MINGW LLVM_HAVE_LIBXAR diff --git a/lld/test/ELF/compressed-debug-input-zstd.s b/lld/test/ELF/compressed-debug-input-zstd.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/compressed-debug-input-zstd.s @@ -0,0 +1,42 @@ +# REQUIRES: x86, zstd + +# RUN: llvm-mc -filetype=obj -triple=x86_64 --compress-debug-sections=zstd %s -o %t.o + +# RUN: ld.lld %t.o -o %t.so -shared +# RUN: llvm-readobj --sections --section-data %t.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: +# 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: 756E7369 676E6564 20696E74 00636861 |unsigned int.cha| +# DATA-NEXT: 0010: 7200756E 7369676E 65642063 68617200 |r.unsigned char.| +# DATA-NEXT: 0020: 73686F72 7420756E 7369676E 65642069 |short unsigned i| +# DATA-NEXT: 0030: 6E74006C 6F6E6720 756E7369 676E6564 |nt.long unsigned| +# DATA-NEXT: 0040: 20696E74 00 | int.| +# DATA-NEXT: ) +# DATA-NEXT: } + +.section .debug_str,"MS",@progbits,1 +.LASF2: + .string "short unsigned int" +.LASF3: + .string "unsigned int" +.LASF0: + .string "long unsigned int" +.LASF8: + .string "char" +.LASF1: + .string "unsigned char" diff --git a/lld/test/ELF/compressed-input-err-zstd.s b/lld/test/ELF/compressed-input-err-zstd.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/compressed-input-err-zstd.s @@ -0,0 +1,18 @@ +# UNSUPPORTED: zstd +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: {{.*}}.o:(.debug_info) is compressed with ELFCOMPRESS_ZSTD, but lld is not built with zstd support + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_PROGBITS + Name: .debug_info + Flags: [ SHF_COMPRESSED ] + AddressAlign: 8 + Content: "020000000000000000000000000000000100000000000000789c030000000001" diff --git a/lld/test/ELF/gdb-index.s b/lld/test/ELF/gdb-index.s --- a/lld/test/ELF/gdb-index.s +++ b/lld/test/ELF/gdb-index.s @@ -22,6 +22,12 @@ # RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s --check-prefix=DWARF # RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SECTION +# RUN: %if zstd %{ llvm-mc -compress-debug-sections=zlib -filetype=obj -triple=x86_64 %p/Inputs/gdb-index.s -o %t2.o %} +# RUN: %if zstd %{ ld.lld --gdb-index %t1.o %t2.o -o %t %} +# RUN: %if zstd %{ llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM %} +# RUN: %if zstd %{ llvm-dwarfdump --gdb-index %t | FileCheck %s --check-prefix=DWARF %} +# RUN: %if zstd %{ llvm-readelf -S %t | FileCheck %s --check-prefix=SECTION %} + # DISASM: Disassembly of section .text: # DISASM-EMPTY: # DISASM: : diff --git a/lld/test/lit.site.cfg.py.in b/lld/test/lit.site.cfg.py.in --- a/lld/test/lit.site.cfg.py.in +++ b/lld/test/lit.site.cfg.py.in @@ -18,6 +18,7 @@ config.target_triple = "@LLVM_TARGET_TRIPLE@" config.python_executable = "@Python3_EXECUTABLE@" config.have_zlib = @LLVM_ENABLE_ZLIB@ +config.have_zstd = @LLVM_ENABLE_ZSTD@ config.have_libxar = @LLVM_HAVE_LIBXAR@ config.have_libxml2 = @LLVM_ENABLE_LIBXML2@ config.sizeof_void_p = @CMAKE_SIZEOF_VOID_P@