Skip to content

Commit cfa9769

Browse files
committed
[ELF] Retain uncompressed if compressed content is larger
--compress-debug-sections in GNU ld, gas, and LLVM integrated assembler retain the uncompressed content if the compressed content is larger. This patch also updates the manpage (-O2 does not enable zlib level 6) and fixes a crash of --compress-sections when the uncompressed section is empty.
1 parent e53c535 commit cfa9769

File tree

5 files changed

+18
-14
lines changed

5 files changed

+18
-14
lines changed

lld/ELF/Options.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ defm compress_debug_sections:
6969

7070
defm compress_sections: EEq<"compress-sections",
7171
"Compress output sections that match the glob and do not have the SHF_ALLOC flag. "
72+
"The sections remain uncompressed if compressed content would be larger. "
7273
"The compression level is <level> (if specified) or a default speed-focused level">,
7374
MetaVarName<"<section-glob>={none,zlib,zstd}[:level]">;
7475

lld/ELF/OutputSections.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,9 +344,10 @@ template <class ELFT> void OutputSection::maybeCompress() {
344344
(void)sizeof(Elf_Chdr);
345345

346346
DebugCompressionType ctype = DebugCompressionType::None;
347+
size_t compressedSize = sizeof(Elf_Chdr);
347348
unsigned level = 0; // default compression level
348349
if (!(flags & SHF_ALLOC) && config->compressDebugSections &&
349-
name.starts_with(".debug_") && size)
350+
name.starts_with(".debug_"))
350351
ctype = *config->compressDebugSections;
351352
for (auto &[glob, t, l] : config->compressSections)
352353
if (glob.match(name))
@@ -360,7 +361,6 @@ template <class ELFT> void OutputSection::maybeCompress() {
360361
}
361362

362363
llvm::TimeTraceScope timeScope("Compress sections");
363-
compressed.uncompressedSize = size;
364364
auto buf = std::make_unique<uint8_t[]>(size);
365365
// Write uncompressed data to a temporary zero-initialized buffer.
366366
{
@@ -378,7 +378,6 @@ template <class ELFT> void OutputSection::maybeCompress() {
378378
[[maybe_unused]] constexpr size_t shardSize = 1 << 20;
379379
auto shardsIn = split(ArrayRef<uint8_t>(buf.get(), size), shardSize);
380380
const size_t numShards = shardsIn.size();
381-
compressed.numShards = numShards;
382381
auto shardsOut = std::make_unique<SmallVector<uint8_t, 0>[]>(numShards);
383382

384383
#if LLVM_ENABLE_ZSTD
@@ -409,9 +408,8 @@ template <class ELFT> void OutputSection::maybeCompress() {
409408
shardsOut[i] = std::move(out);
410409
});
411410
compressed.type = ELFCOMPRESS_ZSTD;
412-
size = sizeof(Elf_Chdr);
413411
for (size_t i = 0; i != numShards; ++i)
414-
size += shardsOut[i].size();
412+
compressedSize += shardsOut[i].size();
415413
}
416414
#endif
417415

@@ -434,18 +432,23 @@ template <class ELFT> void OutputSection::maybeCompress() {
434432

435433
// Update section size and combine Alder-32 checksums.
436434
uint32_t checksum = 1; // Initial Adler-32 value
437-
size = sizeof(Elf_Chdr) + 2; // Elf_Chdir and zlib header
435+
compressedSize += 2; // Elf_Chdir and zlib header
438436
for (size_t i = 0; i != numShards; ++i) {
439-
size += shardsOut[i].size();
437+
compressedSize += shardsOut[i].size();
440438
checksum = adler32_combine(checksum, shardsAdler[i], shardsIn[i].size());
441439
}
442-
size += 4; // checksum
440+
compressedSize += 4; // checksum
443441
compressed.type = ELFCOMPRESS_ZLIB;
444442
compressed.checksum = checksum;
445443
}
446444
#endif
447445

446+
if (compressedSize >= size)
447+
return;
448+
compressed.uncompressedSize = size;
448449
compressed.shards = std::move(shardsOut);
450+
compressed.numShards = numShards;
451+
size = compressedSize;
449452
flags |= SHF_COMPRESSED;
450453
}
451454

lld/docs/ld.lld.1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ Alias for
148148
.Fl -color-diagnostics Ns = Ns Cm auto .
149149
.It Fl -compress-debug-sections Ns = Ns Ar value
150150
Compress DWARF debug sections.
151+
The sections remain uncompressed if compressed content would be larger.
151152
.Cm value
152153
may be
153154
.Pp
@@ -163,6 +164,7 @@ Use the default compression level in zstd.
163164
.Pp
164165
.It Fl -compress-sections Ns = Ns Ar section-glob={none,zlib,zstd}[:level]
165166
Compress output sections that match the glob and do not have the SHF_ALLOC flag.
167+
The matched sections remain uncompressed if compressed content would be larger.
166168
The compression level is
167169
.Cm level
168170
(if specified) or a default speed-focused level.
@@ -420,9 +422,7 @@ Disable string merging.
420422
.It Cm 1
421423
Enable string merging.
422424
.It Cm 2
423-
Enable string tail merging. If
424-
.Fl -compress-debug-sections
425-
is given, compress debug sections at compression level 6 instead of 1.
425+
Enable string tail merging.
426426
.El
427427
.Pp
428428
.Fl O Ns Cm 1

lld/test/ELF/compress-debug-sections-zstd.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
# OUTPUT-SEC: .debug_str PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 01 MSC 0 0 1
2323
# OUTPUT-SEC-NEXT: .debug_frame PROGBITS [[#%x,]] [[#%x,]] 000000 00 0 0 1
24-
# OUTPUT-SEC-NEXT: .debug_loc PROGBITS [[#%x,]] [[#%x,]] [[#%x,]] 00 C 0 0 1
24+
# OUTPUT-SEC-NEXT: .debug_loc PROGBITS [[#%x,]] [[#%x,]] 000010 00 0 0 1
2525

2626
.section .debug_str,"MS",@progbits,1
2727
.LASF2:

lld/test/ELF/compress-sections.s

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
# CHECK2-NEXT: foo1 PROGBITS [[#%x,FOO1:]] [[#%x,]] [[#%x,]] 00 A 0 0 8
2626
# CHECK2-NEXT: .text PROGBITS [[#%x,TEXT:]] [[#%x,]] [[#%x,]] 00 AX 0 0 4
2727
# CHECK2: nonalloc0 PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 C 0 0 1
28-
# CHECK2-NEXT: nonalloc1 PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 0 0 8
29-
# CHECK2-NEXT: smallc0 PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 C 0 0 1
28+
# CHECK2-NEXT: nonalloc1 PROGBITS 0000000000000000 [[#%x,]] 000088 00 0 0 8
29+
# CHECK2-NEXT: smallc0 PROGBITS 0000000000000000 [[#%x,]] 00000c 00 0 0 1
3030
# CHECK2-NEXT: .debug_str PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 01 MSC 0 0 1
3131

3232
# CHECK2: 0000000000000090 0 NOTYPE LOCAL DEFAULT [[#]] (nonalloc0) sym0

0 commit comments

Comments
 (0)