This is an archive of the discontinued LLVM Phabricator instance.

[Linker] Support weak symbols in nodeduplicate COMDAT group
ClosedPublic

Authored by phosek on Aug 25 2021, 1:15 AM.

Details

Summary

When a nodeduplicate COMDAT group contains a weak symbol, choose
a non-weak symbol (or one of the weak ones) rather than reporting
an error. This should address issue PR51394.

With the current IR representation, a generic comdat nodeduplicate
semantics is not representable for LTO. In the linker, sections and
symbols are separate concepts. A dropped weak symbol does not force the
defining input section to be dropped as well (though it can be collected
by GC). In the IR, when a weak linkage symbol is dropped, its associate
section content is dropped as well.

For InstrProfiling, which is where ran into this issue in PR51394, the
deduplication semantic is a sufficient workaround.

Diff Detail

Event Timeline

phosek created this revision.Aug 25 2021, 1:15 AM
phosek requested review of this revision.Aug 25 2021, 1:15 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 25 2021, 1:15 AM

This is a workaround instead of a proper fix. comdat nodeduplicate does not perform deduplication. LinkFromSrc is for deduplication, so not suitable.
All the members should be tested.
For InstrProfiling.cpp, I agree that the deduplication semantic is a sufficient workaround.

llvm/test/Linker/comdat4.ll
2 ↗(On Diff #368573)

Use split-file to avoid an one-off Inputs/ file

The description should call out that with current IR, a generic comdat nodeduplicate for regular LTO is not representable.

In the linker, sections and symbols are separate concepts. A dropped weak symbol does not force the drop of the defining input section (though can be collected by GC).
While in the IR, when a weak linkage symbol is dropped, its associate section content is dropped as well.
profc and profd must be parallel, so we need to be careful.
For their regular LTO behavior, a comdat any happens to work because we don't really the need other members in the comdat whose leader is weak.

phosek marked an inline comment as done.Aug 27 2021, 12:29 AM
phosek added a subscriber: mcgrathr.

The description should call out that with current IR, a generic comdat nodeduplicate for regular LTO is not representable.

In the linker, sections and symbols are separate concepts. A dropped weak symbol does not force the drop of the defining input section (though can be collected by GC).
While in the IR, when a weak linkage symbol is dropped, its associate section content is dropped as well.
profc and profd must be parallel, so we need to be careful.
For their regular LTO behavior, a comdat any happens to work because we don't really the need other members in the comdat whose leader is weak.

@mcgrathr suggested using a COMDAT group anytime the instrumented function is weak, I can implement that solution instead if that's fine with you.

If you mean zero flag groups for export linkage functions and GRP_COMDAT groups for weak linkage functions.
If the symbol resolution says the strong symbol overrides the weak one, no rule says that the GRP_COMDAT group should be discarded because it is unclear it is a non-prevailing group.
For local linkage functions, we'd still use a zero flag group.

Symbol resolution is orthogonal to GRP_COMDAT selection.
Switching to GRP_COMDAT does not imply that the weak leader symbol makes the group discarded.
Therefore, I think switching the group flag doesn't help.
The fundamental issue is that LLVM IR is symbol oriented. It cannot encode the section oriented ELF group semantics.

Since GRP_COMDAT doesn't help, I think accepting the deficiency and using comdat any like semantics for regular LTO is fine.
We just need to be careful not to request too much from comdat nodeduplicate.

phosek updated this revision to Diff 369141.Aug 27 2021, 10:50 AM
phosek edited the summary of this revision. (Show Details)
MaskRay accepted this revision.Aug 27 2021, 1:22 PM
This revision is now accepted and ready to land.Aug 27 2021, 1:22 PM
MaskRay added a comment.EditedAug 27 2021, 11:20 PM

Err, this can be properly fixed by renaming to a private (ELF) internal (COFF) linkage symbol. Let me take a stab.

But this should be a safe choice for release/13.x

More complete (though still partial) fix: D108879

More complete (though still partial) fix: D108879

Do you prefer landing your change instead and abandoning this one?

More complete (though still partial) fix: D108879

Do you prefer landing your change instead and abandoning this one?

Landing just D108879 if no rush for release/13.x:) (which I assume yes because the issue is from a proprietary group which uses rolling updates instead of releases).

More complete (though still partial) fix: D108879

Do you prefer landing your change instead and abandoning this one?

Landing just D108879 if no rush for release/13.x:) (which I assume yes because the issue is from a proprietary group which uses rolling updates instead of releases).

I think we need to cherry pick this into 13.x. I can land this one and prepare a cherry-pick for 13.x, and we can then land D108879 on top as a more complete solution, is that OK with you?

It is ok. You will need to rebase anyway ... because I've changed the tests and some LinkFromSrc.

bd1976llvm added a subscriber: bd1976llvm.EditedSep 6 2021, 10:28 AM

Thanks for the timely fix :)

I noticed that Comdat::SelectionKind::NoDeduplicate is also used for the code/data added when using sanitizers. Can I get your opinion on whether this fix is sufficient for that case as well?

I looked at D108879 but that is only required when the initializers of variables in the discarded comdat are important and I don't *think* that's the case when using sanitizers - but I'm not very familiar with the area.

Thanks in advance!