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 decompressAux(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) + + ": decompress failed: " + llvm::toString(std::move(e))); +} + void InputSectionBase::decompress() 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) + - ": decompress failed: " + llvm::toString(std::move(e))); + invokeELFT(decompressAux, *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) + ": decompress failed: " + llvm::toString(std::move(e))); uint8_t *bufEnd = buf + size; diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -26,6 +26,9 @@ ELF Improvements ---------------- +* ``ELFCOMPRESS_ZSTD`` compressed input sections are now supported. + (`D129406 `_) + Breaking changes ---------------- 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/compress-debug-sections-zstd.s b/lld/test/ELF/compress-debug-sections-zstd.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/compress-debug-sections-zstd.s @@ -0,0 +1,26 @@ +# 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-readelf -S -x .debug_str %t.so | FileCheck %s + +# CHECK: .debug_str PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 01 MS 0 0 1 +# CHECK: Hex dump of section '.debug_str': +# CHECK-NEXT: 0x00000000 756e7369 676e6564 20696e74 00636861 unsigned int.cha +# CHECK-NEXT: 0x00000010 7200756e 7369676e 65642063 68617200 r.unsigned char. +# CHECK-NEXT: 0x00000020 73686f72 7420756e 7369676e 65642069 short unsigned i +# CHECK-NEXT: 0x00000030 6e74006c 6f6e6720 756e7369 676e6564 nt.long unsigned +# CHECK-NEXT: 0x00000040 20696e74 00 int. + +.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@