diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -848,27 +848,34 @@ auto &MC = Asm.getContext(); const auto &MAI = MC.getAsmInfo(); - bool CompressionEnabled = - MAI->compressDebugSections() != DebugCompressionType::None; - if (!CompressionEnabled || !SectionName.startswith(".debug_")) { + const DebugCompressionType CompressionType = MAI->compressDebugSections(); + if (CompressionType == DebugCompressionType::None || + !SectionName.startswith(".debug_")) { Asm.writeSectionData(W.OS, &Section, Layout); return; } - assert(MAI->compressDebugSections() == DebugCompressionType::Z && - "expected zlib style compression"); - SmallVector UncompressedData; raw_svector_ostream VecOS(UncompressedData); Asm.writeSectionData(VecOS, &Section, Layout); - - SmallVector Compressed; - const uint32_t ChType = ELF::ELFCOMPRESS_ZLIB; - compression::zlib::compress( + ArrayRef Uncompressed = makeArrayRef(reinterpret_cast(UncompressedData.data()), - UncompressedData.size()), - Compressed); + UncompressedData.size()); + SmallVector Compressed; + uint32_t ChType; + switch (CompressionType) { + case DebugCompressionType::None: + llvm_unreachable("has been handled"); + case DebugCompressionType::Z: + ChType = ELF::ELFCOMPRESS_ZLIB; + break; + case DebugCompressionType::Zstd: + ChType = ELF::ELFCOMPRESS_ZSTD; + break; + } + compression::compress(compression::Params(CompressionType), Uncompressed, + Compressed); if (!maybeWriteCompression(ChType, UncompressedData.size(), Compressed, Sec.getAlignment())) { W.OS << UncompressedData; diff --git a/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s b/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s --- a/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s +++ b/llvm/test/MC/ELF/compress-debug-sections-zlib-unavailable.s @@ -1,4 +1,5 @@ // REQUIRES: !zlib // RUN: not llvm-mc -filetype=obj -compress-debug-sections=zlib -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s -// CHECK: llvm-mc{{[^:]*}}: error: build tools with zlib to enable -compress-debug-sections +// CHECK: llvm-mc{{[^:]*}}: error: build tools with LLVM_ENABLE_ZLIB to enable --compress-debug-sections=zlib +// CHECK-NOT: {{.}} diff --git a/llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s b/llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/compress-debug-sections-zstd-unavailable.s @@ -0,0 +1,5 @@ +# UNSUPPORTED: zstd +# RUN: not llvm-mc -filetype=obj -compress-debug-sections=zstd -triple x86_64 %s 2>&1 | FileCheck %s + +# CHECK: error: --compress-debug-sections: LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at build time +# CHECK-NOT: {{.}} diff --git a/llvm/test/MC/ELF/compress-debug-sections-zstd.s b/llvm/test/MC/ELF/compress-debug-sections-zstd.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/compress-debug-sections-zstd.s @@ -0,0 +1,115 @@ +# REQUIRES: zstd + +# RUN: llvm-mc -filetype=obj -triple=x86_64 -compress-debug-sections=zstd %s -o %t +# RUN: llvm-readelf -S %t | FileCheck %s --check-prefix=SEC +# RUN: llvm-objdump -s %t | FileCheck %s + +## Check that the large debug sections .debug_line and .debug_frame are compressed +## and have the SHF_COMPRESSED flag. +# SEC: .nonalloc PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 0 0 1 +# SEC: .debug_line PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 C 0 0 8 +# SEC: .debug_abbrev PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 0 0 1 +# SEC: .debug_info PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 0 0 1 +# SEC: .debug_str PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 01 MSC 0 0 8 +# SEC: .debug_frame PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 C 0 0 8 + +# CHECK: Contents of section .debug_line +## ch_type == ELFCOMPRESS_ZSTD (2) +# CHECK-NEXT: 0000 02000000 00000000 55010000 00000000 +# CHECK-NEXT: 0010 01000000 00000000 {{.*}} + +## The compress/decompress round trip should be identical to the uncompressed output. +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.uncom +# RUN: llvm-objcopy --decompress-debug-sections %t %t.decom +# RUN: cmp %t.uncom %t.decom + +## Don't compress a section not named .debug_*. + .section .nonalloc,"",@progbits +.rept 50 +.asciz "aaaaaaaaaa" +.endr + + .section .debug_line,"",@progbits + + .section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .section .debug_info,"",@progbits + .long 12 # Length of Unit + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_comp_dir + + .text +foo: + .cfi_startproc + .file 1 "Driver.ii" + +.rept 3 +.ifdef I386 + pushl %ebp + .cfi_def_cfa_offset 8 + .cfi_offset %ebp, -8 + movl %esp, %ebp + .cfi_def_cfa_register %ebp + pushl %ebx + pushl %edi + pushl %esi + .cfi_offset %esi, -20 + .cfi_offset %edi, -16 + .cfi_offset %ebx, -12 + .loc 1 1 1 prologue_end + popl %esi + popl %edi + popl %ebx + popl %ebp + .cfi_def_cfa %esp, 4 +.else + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbx + .cfi_offset %rbx, -56 + .cfi_offset %r12, -48 + .cfi_offset %r13, -40 + .cfi_offset %r14, -32 + .cfi_offset %r15, -24 + .loc 1 1 1 prologue_end + popq %rbx + popq %r12 + popq %r13 + popq %r14 + popq %r15 + popq %rbp + .cfi_def_cfa %rsp, 8 +.endif +.endr + +# pad out the line table to make sure it's big enough to warrant compression + .irpc i, 123456789 + .irpc j, 0123456789 + .loc 1 \i\j \j + nop + .endr + .endr + .cfi_endproc + .cfi_sections .debug_frame + + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "perfectly compressable data sample *****************************************" diff --git a/llvm/tools/llvm-mc/llvm-mc.cpp b/llvm/tools/llvm-mc/llvm-mc.cpp --- a/llvm/tools/llvm-mc/llvm-mc.cpp +++ b/llvm/tools/llvm-mc/llvm-mc.cpp @@ -76,8 +76,8 @@ cl::init(DebugCompressionType::None), cl::desc("Choose DWARF debug sections compression:"), cl::values(clEnumValN(DebugCompressionType::None, "none", "No compression"), - clEnumValN(DebugCompressionType::Z, "zlib", - "Use zlib compression")), + clEnumValN(DebugCompressionType::Z, "zlib", "Use zlib"), + clEnumValN(DebugCompressionType::Zstd, "zstd", "Use zstd")), cl::cat(MCCategory)); static cl::opt @@ -399,15 +399,15 @@ assert(MAI && "Unable to create target asm info!"); MAI->setRelaxELFRelocations(RelaxELFRel); - if (CompressDebugSections != DebugCompressionType::None) { - if (!compression::zlib::isAvailable()) { + if (const char *Reason = compression::getReasonIfUnsupported( + compression::formatFor(CompressDebugSections))) { WithColor::error(errs(), ProgName) - << "build tools with zlib to enable -compress-debug-sections"; + << "--compress-debug-sections: " << Reason; return 1; } - MAI->setCompressDebugSections(CompressDebugSections); } + MAI->setCompressDebugSections(CompressDebugSections); MAI->setPreserveAsmComments(PreserveComments); // Package up features to be passed to target/subtarget