This is an archive of the discontinued LLVM Phabricator instance.

[MC][ELF] Support for zero flag section groups
ClosedPublic

Authored by phosek on Feb 1 2021, 11:47 PM.

Details

Summary

This change introduces support for zero flag ELF section groups to LLVM.
LLVM already supports COMDAT sections, which in ELF are a special type
of ELF section groups. These are generally useful to enable linker GC
where you want a group of sections to always travel together, that is to
be either retained or discarded as a whole, but without the COMDAT
semantics. Other ELF assemblers already support zero flag ELF section
groups and this change helps us reach feature parity.

Diff Detail

Event Timeline

phosek created this revision.Feb 1 2021, 11:47 PM
phosek requested review of this revision.Feb 1 2021, 11:47 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 1 2021, 11:47 PM
phosek added a subscriber: leonardchan.EditedFeb 1 2021, 11:56 PM

The support for ELF section groups appeared several times in various contexts over the last few months, most notably this thread https://groups.google.com/g/generic-abi/c/hgx_m1aXqUo. Most recently, we ran into the lack of support for ELF section groups in @leonardchan's work on relative vtable C++ ABI where we believe it to be the most optimal way to enable garbage collection.

I wanted to see how difficult it'd be to implement the support for ELF section groups in LLVM and lld and as you can see, it wasn't all that hard. While the change touches many different places, it is mostly mechanical.

I wanted to get some early feedback from you before I spend more time on this. Do you think this is the right direction?

In particular, one aspect I'm not particular happy about is the IR representation. Ideally, I'd want a representation that allows global object to be either in COMDAT or a section group, but not both, and ideally doesn't rely on verifier to ensure correctness. One idea I had would be to introduce a new comdat kind: group. This would achieve my goal, but semantically seems backwards (in ELF, COMDAT is a special kind of group, not the other way round).

Thank you in advance for any suggestions and feedback on the implementation.

MaskRay added a comment.EditedFeb 2 2021, 12:20 AM

(It is running late. I just quickly skimmed through the patch.)
Thanks for working on this. This is useful. The subject should be changed to mention "zero section group flag" because GRP_COMDAT is also a section group flag and that has been available for years.

I think we need a binary format level patch, an lld/ELF patch, and another patch based on the binary format patch.

For the binary format patch, we need some test/MC tests. We need one aoG test to check that linked-to argument is placed before the group signature.
This part is uncontroversial as GNU as already has the syntax support.

For the IR patch, I haven't thought clearly whether it should be similar to the existing comdat syntax or use an opaque string.
You may want to pull in reviewers working in that area.

This deserves an llvm-dev topic.

MaskRay added a subscriber: grimar.

I prototyped something like this on an asm/linker level only (i.e. not the IR stuff), as part of some downstream experimentation work I did several years ago. This doesn't look all that dissimilar, which is reassuring, and probably suggests your on the right path to me.

+1 to splitting up the patch into separate patches. I think an LLD patch, an LLVM IR patch, and an assembler patch would be sufficient. I don't have any real expertees in the LLVM IR area, so can't be relied on to review that bit!

Re. how to indicate this in IR, I think a group tag is probably the way forawrd, which I think is what you've done here. You could say something like "group == in a regular group", "comdat == in a comdat group", "group comdat == in a comdat group". In other words, comdat on its own implies group. You wouldn't then need a verification check to show people haven't included them both. I don't know how practical this is however.

llvm/lib/IR/Verifier.cpp
589 ↗(On Diff #320692)

I guess to me a section is either "in a group" (not has a group), or in a comdat (which is a special kind of group), so perhaps the first bit of this message should be tweaked. Possibly we could add "non-comdat" before "group" to emphasise the difference, and maybe even add "group" after "comdat" too.

bcain added a subscriber: bcain.Feb 2 2021, 7:12 AM

Reverse ping:) Got a chance to send a proposal about the IR syntax on llvm-dev?

phosek added a subscriber: gulfem.Feb 10 2021, 10:51 PM

Reverse ping:) Got a chance to send a proposal about the IR syntax on llvm-dev?

I like the suggestion from @jhenderson which I also ran by @leonardchan and @gulfem who are also in favor, but I'm also happy to check with llvm-dev to see if anyone has better idea.

phosek updated this revision to Diff 323498.Feb 12 2021, 4:18 PM
phosek retitled this revision from Support for ELF section groups to [MC][ELF] Support for zero flag section groups.
phosek edited the summary of this revision. (Show Details)
phosek added a subscriber: rnk.

I split the linker part into D96636 and I've updated the change to use comdat noduplicates to represent zero flag ELF section groups as suggested by @rnk in https://lists.llvm.org/pipermail/llvm-dev/2021-February/148483.html

MaskRay added inline comments.Feb 13 2021, 3:07 PM
llvm/include/llvm/MC/MCContext.h
496–497

Group == "" means a non-SHF_GROUP section. IsComdat = true can be misleading for such use cases.

We should pick a variable which defaults to false here.

NoDeduplicates is a PE-COFF specific name, and we should stick with ELF naming here. So a concise name indicating zero section group flags should be used.

phosek updated this revision to Diff 323595.Feb 13 2021, 10:20 PM
phosek added inline comments.Feb 13 2021, 10:23 PM
llvm/include/llvm/MC/MCContext.h
496–497

I used IsComdat = true because I was worried that updating every existing call site is going to be too much effort, but turned it wasn't so bad so I removed the default argument.

I think that having /*IsComdat=*/true or /*IsComdat=*/false explicitly in the code is actually nice because it's clear which type of group we're requesting.

Let me know what you think.

MaskRay added inline comments.Feb 14 2021, 10:02 AM
llvm/include/llvm/MC/MCContext.h
496–497

If you flip the default to /*IsComdat=*/false, it looks good to me.

That means a generic section has Group=="" && !IsComdat.
A comdat section needs Group!="" && IsComdat.

phosek marked 2 inline comments as done.Feb 14 2021, 1:17 PM
phosek added inline comments.Feb 14 2021, 2:44 PM
llvm/include/llvm/MC/MCContext.h
496–497

This is done in the latest revision.

Mostly LG.

llvm/include/llvm/MC/MCContext.h
496–497

Thanks. The large number of getELFSection overloads is somewhat difficult to manage...I deleted some overloads. Someone may want to further clean up them...

llvm/test/CodeGen/X86/group.ll
1 ↗(On Diff #323595)

Add a file-level comment explaining the purpose of the test.

3 ↗(On Diff #323595)

Add {{$}} otherwise they don't catch accidental ,comdat

I've not really looked into this and I'm quite busy at the moment, so am happy to go with @MaskRay's opinion here when he's happy.

phosek updated this revision to Diff 323922.Feb 16 2021, 1:45 AM
phosek marked 2 inline comments as done.
MaskRay added inline comments.Feb 16 2021, 10:36 AM
llvm/include/llvm/MC/MCSectionELF.h
42

/// The section group signature symbol (if not null) and a bool indicating whether this is within a GRP_COMDAT group.

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
854

StringRef Group

StringRef initializes to an empty string.

859

Can you check whether other selection kinds are rejected elsewhere?

If not, we should report an error for non-any-non-nodeduplicates kinds.

llvm/lib/MC/MCParser/ELFAsmParser.cpp
428

Perhaps assign IsComdat to false here to prevent pitfalls.

llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
1206

This is likely wrong, but the existing tests are not good enough to catch the issue.

void ext();
inline void foo() {
  try {
    ext();
  } catch (...) {
  }
}
void bar() {
  foo();
}

clang -target armv7-linux-gnueabi -c a.cc

.ARM.extab.text._Z3foov and .ARM.exidx.text._Z3foov should be in GRP_COMDAT groups, not zero flag groups.

Given the risk, consider making a precursor commit dropping , "" so that the patch can be more focused on functionality changes.

phosek updated this revision to Diff 324056.Feb 16 2021, 11:09 AM
phosek marked 5 inline comments as done.
phosek added inline comments.
llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
859

They're checked in getELFComdat which reports an error for unsupported kinds (see the lines 525-529).

llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
1206

Thanks for catching this, I made this change in earlier revision when the meaning of the boolean was flipped and I forgot to update this instance. I've also included comment.

MaskRay accepted this revision.Feb 16 2021, 1:03 PM

Thanks!

This revision is now accepted and ready to land.Feb 16 2021, 1:03 PM
This revision was automatically updated to reflect the committed changes.