This is an archive of the discontinued LLVM Phabricator instance.

[LLD] [COFF] Cope with GCC produced weak aliases referring to comdat functions
ClosedPublic

Authored by mstorsjo on Sep 27 2018, 4:18 AM.

Details

Summary

For certain cases of inline functions written to comdat sections, GCC 5.x produces a weak symbol in addition, which would end up undefined in some cases.

This no longer seems to happen with GCC 6.x or newer, so this might not be strictly necessary. Also, when linking clang.exe, almost all symbols come from static libraries, so they just end up left as Lazy instead of Undefined, which makes the link succeed.

Diff Detail

Repository
rL LLVM

Event Timeline

mstorsjo created this revision.Sep 27 2018, 4:18 AM
ruiu added a comment.Sep 27 2018, 4:17 PM

Do you know why gcc creates this .weak.* symbol in the first place, and is there any real use of .weak.* symbol in the wild?

Do you know why gcc creates this .weak.* symbol in the first place, and is there any real use of .weak.* symbol in the wild?

For the normal case of weak symbols (if the user explicitly uses __attribute__((weak))), GCC creates such a symbol because there is no other symbol available for the concrete implementation of the function. For this particular case in combination with inline functions, I think GCC didn't need to produce such a symbol (and didn't need to produce any weak alias at all), as GCC 6.x and newer no longer does it.

If you mean if any actual code in the wild intentionally uses __attribute__((weak)) for COFF targets? Very little I think, but I have seen it in use within libgcc use it in a few places at least.

Also, just to be clear - this patch doesn't skip all of these symbols. Only in the case if such a symbol points to a discarded comdat section, we skip the symbol so that we don't fail the link just for an unused symbol.

ruiu added a comment.Sep 28 2018, 10:57 AM

The "proper" way of implementing a weak alias is to embed a "/alternatename" command line option to a .drectve section, so it is unfortunate that gcc took a different approach.

Is there any way to distinguish a symbol explicitly annotated with __attribute__((weak)) and an inline function?

The "proper" way of implementing a weak alias is to embed a "/alternatename" command line option to a .drectve section, so it is unfortunate that gcc took a different approach.

Is there any way to distinguish a symbol explicitly annotated with __attribute__((weak)) and an inline function?

Yes, they are completely different things. A normal inline function with GCC works just as it does with MSVC, you get a COMDAT symbol. A __attribute__((weak)) func() symbol gets you a COFF weak external named func, which points at .weak.func.<somename>, which LLD can handle just fine (MSVC import libraries use COFF weak externals occasionally as well).

There's just two minor extra details:

  • As an "extra feature" maybe, GCC/binutils allows you to have multiple distinct weak implementations of a function. If there's no strong definition, the linker picks the first weak one it saw. This is handled by the other patch, D52601, and IMO is rather straightforward.
  • As a bug(?) in GCC 5.x (and maybe older), certain special cases of inline templated functions in C++ can produce a weak symbol pointing to the COMDAT symbol. This is handled by this patch.
rnk accepted this revision.Oct 5 2018, 11:58 AM

What the heck, one more weird thing.

This revision is now accepted and ready to land.Oct 5 2018, 11:58 AM
This revision was automatically updated to reflect the committed changes.