Skip to content
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

[llvm-objcopy] Remove empty SHT_GROUP sections #97141

Merged
merged 1 commit into from
Jul 8, 2024

Conversation

chestnykh
Copy link
Contributor

@chestnykh chestnykh commented Jun 29, 2024

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

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Collaborator

llvmbot commented Jun 29, 2024

@llvm/pr-subscribers-llvm-binary-utilities

Author: Dmitriy Chestnykh (chestnykh)

Changes

Currently llvm-strip in --strip-debug mode doesn't remove such sections. This behavior can lead to incompatibilities with GNU binutils (for examples ld.bfd 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


Full diff: https://github.com/llvm/llvm-project/pull/97141.diff

3 Files Affected:

  • (modified) llvm/lib/ObjCopy/ELF/ELFObject.cpp (+9-1)
  • (modified) llvm/lib/ObjCopy/ELF/ELFObject.h (+2)
  • (added) llvm/test/tools/llvm-objcopy/ELF/strip-debug-empty-group.test (+25)
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 02591e6f987c2..44181ccd328bf 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2206,8 +2206,16 @@ 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 all together.
   Sections.erase(Iter, std::end(Sections));
+
+  // Finally iterate over all sections and erase empty SHT_GROUP sections.
+  for (auto Iter = Sections.begin(); Iter != Sections.end(); ++Iter) {
+    if (auto GroupSec = dyn_cast<GroupSection>(Iter->get())) {
+      if (GroupSec->getMembersCount() == 0)
+        Sections.erase(Iter);
+    }
+  }
   return Error::success();
 }
 
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 2b1895a30b41e..9bbef268017ea 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -963,6 +963,8 @@ class GroupSection : public SectionBase {
       const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
   void onRemove() override;
 
+  size_t getMembersCount() {return GroupMembers.size(); }
+
   static bool classof(const SectionBase *S) {
     return S->OriginalType == ELF::SHT_GROUP;
   }
diff --git a/llvm/test/tools/llvm-objcopy/ELF/strip-debug-empty-group.test b/llvm/test/tools/llvm-objcopy/ELF/strip-debug-empty-group.test
new file mode 100644
index 0000000000000..26bbde0c603bb
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/strip-debug-empty-group.test
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-strip --strip-debug %t -o %t1
+# RUN: llvm-readelf --section-groups %t1 | FileCheck %s
+
+--- !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
+
+# CHECK: There are no section groups in this file.

@chestnykh chestnykh force-pushed the strip-empty-group branch 2 times, most recently from 0e46333 to ce96728 Compare June 29, 2024 06:37
@chestnykh chestnykh changed the title Remove empty SHT_GROUP sections. [llvm-strip] Remove empty SHT_GROUP sections. Jun 29, 2024
@chestnykh
Copy link
Contributor Author

CC @MaskRay

@tschuett tschuett requested a review from MaskRay June 29, 2024 12:10
@MaskRay
Copy link
Member

MaskRay commented Jun 29, 2024

Currently llvm-strip in --strip-debug mode doesn't remove such sections.

Thanks for noticing this. This applies to other section removal operations like --remove-section, so another test will be useful

@chestnykh
Copy link
Contributor Author

Currently llvm-strip in --strip-debug mode doesn't remove such sections.

Thanks for noticing this. This applies to other section removal operations like --remove-section, so another test will be useful

Added some new runs of llvm-strip + llvm-readelf

Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

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

You can reopen this PR...

# RUN: yaml2obj %s -o %t
# RUN: llvm-strip --strip-debug %t -o %t1
# RUN: llvm-readelf --section-groups %t1 | FileCheck %s

Copy link
Member

Choose a reason for hiding this comment

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

Consider adding another test using --remove-section=.debug_macro

The test file can probably be merged into remove-section-in-group.test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved test to remove-section-in-group.test. Added --remove-section=.debug_macro test (line 44).

Copy link

github-actions bot commented Jun 30, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@chestnykh chestnykh force-pushed the strip-empty-group branch 3 times, most recently from af93768 to 648809a Compare June 30, 2024 18:47
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

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

I think it would be worth a test case where you explicitly remove an empty .group section too, to show that the code handles that successfully (i.e. it doesn't try to remove the same .group section twice and blow up).

llvm/lib/ObjCopy/ELF/ELFObject.cpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

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

LGTM.

@chestnykh chestnykh requested a review from MaskRay July 5, 2024 02:36
for (auto Iter = Sections.begin(); Iter != Sections.end(); ++Iter)
if (auto GroupSec = dyn_cast<GroupSection>(Iter->get()))
if (GroupSec->getMembersCount() == 0)
Sections.erase(Iter);
Copy link
Member

Choose a reason for hiding this comment

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

This is UB and has a quadratic time complexity if the erased elements are many. https://eel.is/c++draft/vector#modifiers-3

"Effects: Invalidates iterators and references at or after the point of the erase."

You could utilize the return address of erase, but to address the time complexity issue you'd need erase_if anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, thanks!

@@ -963,6 +963,8 @@ class GroupSection : public SectionBase {
const DenseMap<SectionBase *, SectionBase *> &FromTo) override;
void onRemove() override;

size_t getMembersCount() { return GroupMembers.size(); }
Copy link
Member

Choose a reason for hiding this comment

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

() const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Currently llvm-strip in --strip-debug mode doesn't remove such sections.
This behavior can lead to incompatibilities with GNU binutils
(for examples ld.bfd 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 llvm#97139
Copy link
Collaborator

@jh7370 jh7370 left a comment

Choose a reason for hiding this comment

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

LGTM again.

@chestnykh
Copy link
Contributor Author

@MaskRay can you merge this PR?

@MaskRay MaskRay changed the title [llvm-strip] Remove empty SHT_GROUP sections. [llvm-objcopy] Remove empty SHT_GROUP sections Jul 8, 2024
@MaskRay MaskRay merged commit 359c64f into llvm:main Jul 8, 2024
5 of 7 checks passed
Copy link

github-actions bot commented Jul 8, 2024

@chestnykh Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested
by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as
the builds can include changes from many authors. It is not uncommon for your
change to be included in a build that fails due to someone else's changes, or
infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself.
This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

MaskRay added a commit that referenced this pull request Jul 9, 2024
This reverts commit 359c64f.

This caused heap-use-after-free. See #98106.
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
This reverts commit 359c64f.

This caused heap-use-after-free. See llvm#98106.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[llvm-strip] llvm-strip doesn't remove empty group sections
4 participants