[ELF] Support ELFCOMPRESS_ZSTD input

so that lld accepts relocatable object files produced by `clang -c -g -gz=zstd`.

We don't want to increase the size of InputSection, so do redundant but cheap
ch_type checks instead.

Differential Revision: https://reviews.llvm.org/D129406
This commit is contained in:
Fangrui Song 2022-09-09 10:25:37 -07:00
parent c682c26942
commit 5e0464e38b
7 changed files with 77 additions and 5 deletions

View File

@ -110,6 +110,18 @@ size_t InputSectionBase::getSize() const {
return rawData.size() - bytesDropped;
}
template <class ELFT>
static void decompressAux(const InputSectionBase &sec, uint8_t *out,
size_t size) {
auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(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 @@ void InputSectionBase::decompress() const {
uncompressedBuf = bAlloc().Allocate<uint8_t>(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 @@ template <typename ELFT> void InputSectionBase::parseCompressedHeader() {
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 @@ template <typename ELFT> void InputSectionBase::parseCompressedHeader() {
uncompressedSize = hdr->ch_size;
alignment = std::max<uint32_t>(hdr->ch_addralign, 1);
rawData = rawData.slice(sizeof(*hdr));
}
InputSection *InputSectionBase::getLinkOrderDep() const {
@ -1219,8 +1232,12 @@ template <class ELFT> void InputSection::writeTo(uint8_t *buf) {
// If this is a compressed section, uncompress section contents directly
// to the buffer.
if (uncompressedSize >= 0) {
auto *hdr = reinterpret_cast<const typename ELFT::Chdr *>(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;

View File

@ -26,6 +26,9 @@ Non-comprehensive list of changes in this release
ELF Improvements
----------------
* ``ELFCOMPRESS_ZSTD`` compressed input sections are now supported.
(`D129406 <https://reviews.llvm.org/D129406>`_)
Breaking changes
----------------

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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: <entrypoint>:

View File

@ -18,6 +18,7 @@ config.lld_tools_dir = lit_config.substitute("@CURRENT_TOOLS_DIR@")
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@