From 359c64f314ad568e78ee9a3723260286e3425c2d Mon Sep 17 00:00:00 2001 From: Dmitriy Chestnykh Date: Mon, 8 Jul 2024 21:50:23 +0300 Subject: [PATCH] [llvm-objcopy] Remove empty SHT_GROUP sections (#97141) Currently `llvm-objcopy/llvm-strip` in `--strip-debug` mode doesn't remove such sections. This behavior can lead to incompatibilities with GNU binutils (for examples ld.bfd before https://sourceware.org/PR20520 cannot process the object file contains empty .group section). The ELF object that contains group section with `.debug_*` sections inside can be obtained by `gcc -g3`. Fix #97139 --- llvm/lib/ObjCopy/ELF/ELFObject.cpp | 11 +++- llvm/lib/ObjCopy/ELF/ELFObject.h | 2 + .../ELF/remove-section-in-group.test | 50 ++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp index 5e6d19b9bfa54b..f9c5d2579be693 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2239,8 +2239,17 @@ Error Object::removeSections( // Transfer removed sections into the Object RemovedSections container for use // later. std::move(Iter, Sections.end(), std::back_inserter(RemovedSections)); - // Now finally get rid of them all together. + // Now get rid of them altogether. Sections.erase(Iter, std::end(Sections)); + + // Finally erase empty SHT_GROUP sections. + llvm::erase_if(Sections, [](const SecPtr &Sec) { + if (auto GroupSec = dyn_cast(Sec.get())) + return GroupSec->getMembersCount() == 0; + + return false; + }); + return Error::success(); } diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index e3c0e7abda16b9..2a9f337c3f3230 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.h +++ b/llvm/lib/ObjCopy/ELF/ELFObject.h @@ -964,6 +964,8 @@ class GroupSection : public SectionBase { const DenseMap &FromTo) override; void onRemove() override; + size_t getMembersCount() const { return GroupMembers.size(); } + static bool classof(const SectionBase *S) { return S->OriginalType == ELF::SHT_GROUP; } diff --git a/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test b/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test index 9e683b9f68c939..ccc1ede0589c17 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test +++ b/llvm/test/tools/llvm-objcopy/ELF/remove-section-in-group.test @@ -1,6 +1,6 @@ ## This checks that the group section is shrunk when its member is removed. -# RUN: yaml2obj %s -o - \ +# RUN: yaml2obj --docnum=1 %s -o - \ # RUN: | llvm-objcopy -R .foo - - \ # RUN: | obj2yaml - \ # RUN: | FileCheck %s @@ -35,3 +35,51 @@ Symbols: - Name: foo_bar_grp Section: .group Binding: STB_GLOBAL + +# RUN: yaml2obj --docnum=2 %s -o %t +# RUN: llvm-objcopy --remove-section=.debug_macro %t +# RUN: llvm-readelf --section-groups %t | FileCheck %s --check-prefix=GROUP-REMOVED + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .group + Type: SHT_GROUP + Info: foo_grp + Members: + - SectionOrType: GRP_COMDAT + - SectionOrType: .debug_macro + - Name: .debug_macro + Type: SHT_PROGBITS + Flags: [ SHF_GROUP ] +Symbols: + - Name: foo_grp + Section: .group + +# GROUP-REMOVED: There are no section groups in this file. + +# RUN: yaml2obj --docnum=3 %s -o %t +# RUN: llvm-objcopy --remove-section=.group %t +# RUN: llvm-readelf --section-groups %t | FileCheck %s --check-prefix=EMPTY-GROUP-REMOVED + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .group + Type: SHT_GROUP + Info: foo_grp + Members: + - SectionOrType: GRP_COMDAT +Symbols: + - Name: foo_grp + Section: .group + +# EMPTY-GROUP-REMOVED: There are no section groups in this file.