Skip to content

[llvm-objcopy] --[de]compress-debug-sections: don't compress SHF_ALLOC sections, only decompress .debug sections #84885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 23 additions & 40 deletions llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,33 +214,32 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
SecName.str().c_str());
}

static bool isCompressable(const SectionBase &Sec) {
return !(Sec.Flags & ELF::SHF_COMPRESSED) &&
StringRef(Sec.Name).starts_with(".debug");
}

static Error replaceDebugSections(
Object &Obj, function_ref<bool(const SectionBase &)> ShouldReplace,
function_ref<Expected<SectionBase *>(const SectionBase *)> AddSection) {
Error Object::compressOrDecompressSections(const CommonConfig &Config) {
// Build a list of the debug sections we are going to replace.
// We can't call `AddSection` while iterating over sections,
// because it would mutate the sections array.
SmallVector<SectionBase *, 13> ToReplace;
for (auto &Sec : Obj.sections())
if (ShouldReplace(Sec))
ToReplace.push_back(&Sec);

// Build a mapping from original section to a new one.
DenseMap<SectionBase *, SectionBase *> FromTo;
for (SectionBase *S : ToReplace) {
Expected<SectionBase *> NewSection = AddSection(S);
if (!NewSection)
return NewSection.takeError();

FromTo[S] = *NewSection;
SmallVector<std::pair<SectionBase *, std::function<SectionBase *()>>, 0>
ToReplace;
for (SectionBase &Sec : sections()) {
if ((Sec.Flags & SHF_ALLOC) || !StringRef(Sec.Name).starts_with(".debug"))
continue;
if (auto *CS = dyn_cast<CompressedSection>(&Sec)) {
if (Config.DecompressDebugSections) {
ToReplace.emplace_back(
&Sec, [=] { return &addSection<DecompressedSection>(*CS); });
}
} else if (Config.CompressionType != DebugCompressionType::None) {
ToReplace.emplace_back(&Sec, [&, S = &Sec] {
return &addSection<CompressedSection>(
CompressedSection(*S, Config.CompressionType, Is64Bits));
});
}
}

return Obj.replaceSections(FromTo);
DenseMap<SectionBase *, SectionBase *> FromTo;
for (auto [S, Func] : ToReplace)
FromTo[S] = Func();
return replaceSections(FromTo);
}

static bool isAArch64MappingSymbol(const Symbol &Sym) {
Expand Down Expand Up @@ -534,24 +533,8 @@ static Error replaceAndRemoveSections(const CommonConfig &Config,
if (Error E = Obj.removeSections(ELFConfig.AllowBrokenLinks, RemovePred))
return E;

if (Config.CompressionType != DebugCompressionType::None) {
if (Error Err = replaceDebugSections(
Obj, isCompressable,
[&Config, &Obj](const SectionBase *S) -> Expected<SectionBase *> {
return &Obj.addSection<CompressedSection>(
CompressedSection(*S, Config.CompressionType, Obj.Is64Bits));
}))
return Err;
} else if (Config.DecompressDebugSections) {
if (Error Err = replaceDebugSections(
Obj,
[](const SectionBase &S) { return isa<CompressedSection>(&S); },
[&Obj](const SectionBase *S) {
const CompressedSection *CS = cast<CompressedSection>(S);
return &Obj.addSection<DecompressedSection>(*CS);
}))
return Err;
}
if (Error E = Obj.compressOrDecompressSections(Config))
return E;

return Error::success();
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/ObjCopy/ELF/ELFObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,7 @@ class Object {

Error removeSections(bool AllowBrokenLinks,
std::function<bool(const SectionBase &)> ToRemove);
Error compressOrDecompressSections(const CommonConfig &Config);
Error replaceSections(const DenseMap<SectionBase *, SectionBase *> &FromTo);
Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
template <class T, class... Ts> T &addSection(Ts &&...Args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Sections:
Type: SHT_PROGBITS
Flags: [ SHF_GROUP ]
Content: '00'
- Name: .debug_alloc
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Content: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
Symbols:
- Type: STT_SECTION
Section: .debug_foo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# COMPRESSED: .debug_foo PROGBITS 0000000000000000 000040 {{.*}} 00 C 0 0 8
# COMPRESSED-NEXT: .notdebug_foo PROGBITS 0000000000000000 {{.*}} 000008 00 0 0 0
# COMPRESSED: .debug_alloc PROGBITS 0000000000000000 {{.*}} 000040 00 A 0 0 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You presumably need changes to the zstd version of this test too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

# UNCOMPRESSED: .debug_foo PROGBITS 0000000000000000 000040 000008 00 0 0 0
# UNCOMPRESSED-NEXT: .notdebug_foo PROGBITS 0000000000000000 {{.*}} 000008 00 0 0 0
# UNCOMPRESSED: .debug_alloc PROGBITS 0000000000000000 {{.*}} 000040 00 A 0 0 0

## Relocations do not change.
# CHECK: Relocation section '.rela.debug_foo' at offset {{.*}} contains 2 entries:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# COMPRESSED: .debug_foo PROGBITS 0000000000000000 000040 {{.*}} 00 C 0 0 8
# COMPRESSED-NEXT: .notdebug_foo PROGBITS 0000000000000000 {{.*}} 000008 00 0 0 0
# COMPRESSED: .debug_alloc PROGBITS 0000000000000000 {{.*}} 000040 00 A 0 0 0
# DECOMPRESSED: .debug_foo PROGBITS 0000000000000000 000040 000008 00 0 0 0
# DECOMPRESSED-NEXT: .notdebug_foo PROGBITS 0000000000000000 {{.*}} 000008 00 0 0 0
# DECOMPRESSED: .debug_alloc PROGBITS 0000000000000000 {{.*}} 000040 00 A 0 0 0

## Relocations do not change.
# CHECK: Relocation section '.rela.debug_foo' at offset {{.*}} contains 2 entries:
Expand Down
36 changes: 36 additions & 0 deletions llvm/test/tools/llvm-objcopy/ELF/decompress-sections.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# REQUIRES: zlib
## Test decompression for different sections.

# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --decompress-debug-sections %t %t.de
# RUN: llvm-readelf -S %t.de | FileCheck %s

# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK: .debug_alloc PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 AC 0 0 0
# CHECK-NEXT: .debug_nonalloc PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 0 0 1
# CHECK-NEXT: .debugx PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 0 0 1
# CHECK-NEXT: nodebug PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 C 0 0 0

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
Machine: EM_X86_64
Sections:
- Name: .debug_alloc
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_COMPRESSED ]
Content: 010000000000000040000000000000000100000000000000789cd36280002d3269002f800151
- Name: .debug_nonalloc
Type: SHT_PROGBITS
Flags: [ SHF_COMPRESSED ]
Content: 010000000000000040000000000000000100000000000000789cd36280002d3269002f800151
- Name: .debugx
Type: SHT_PROGBITS
Flags: [ SHF_COMPRESSED ]
Content: 010000000000000040000000000000000100000000000000789cd36280002d3269002f800151
- Name: nodebug
Type: SHT_PROGBITS
Flags: [ SHF_COMPRESSED ]
Content: 010000000000000040000000000000000100000000000000789cd36280002d3269002f800151