This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Do not leave undefined symbols (specified by -init and -fini) if they are defined in non-fetched archive members
ClosedPublic

Authored by ikudrin on Jul 10 2020, 5:54 AM.

Details

Summary

After D69985, symbols for -init and -fini were unconditionally marked as used even if they were just lazy symbols seen when scanning archives. That resulted in exposing them in the symbol table of an output file, as Undefined, which added unwanted dependencies. The patch fixes the issue by checking the kind of the symbols before marking.

Diff Detail

Event Timeline

ikudrin created this revision.Jul 10 2020, 5:54 AM
MaskRay added a subscriber: aaronpuchert.EditedJul 10 2020, 10:26 AM

I think this is about different expectation of _init and _fini behaviors.

@aaronpuchert Your comment https://bugzilla.opensuse.org/show_bug.cgi?id=1155108#c10 "However, it's actually a bug in all three linkers. It has been fixed in lld just today [1]" made me wonder whether https://bugs.llvm.org/show_bug.cgi?id=43927 was really a linker bug.

I need an LLD reproduce file (obtained via LLD_REPRODUCE=/tmp/rep.tar ... or -Wl,--reproduce=/tmp/rep.tar to under the matter better. An alternative fix to @ikudrin's problem is to revert D69985
openSUSE's OpenMP problem probably should be fixed by adding -u __kmp_internal_end_fini along with -Wl,-fini=__kmp_internal_end_fini instead of relying on the linker retaining the bitcode defined symbols.

aaronpuchert added a comment.EditedJul 10 2020, 1:22 PM

@aaronpuchert Your comment https://bugzilla.opensuse.org/show_bug.cgi?id=1155108#c10 "However, it's actually a bug in all three linkers. It has been fixed in lld just today [1]" made me wonder whether https://bugs.llvm.org/show_bug.cgi?id=43927 was really a linker bug.

The linkers were behaving differently though: lld and bfd dropped the FINI entirely whereas gold had FINI=0, which lead to a crash. Which of these behaviors would be expected?

I need an LLD reproduce file (obtained via LLD_REPRODUCE=/tmp/rep.tar ... or -Wl,--reproduce=/tmp/rep.tar to under the matter better.

It should suffice to have a source file with an otherwise unused hidden visibility function that's used in a -init or -fini linker flag with LTO. If that doesn't help, I can also try putting some files together.

openSUSE's OpenMP problem probably should be fixed by adding -u __kmp_internal_end_fini along with -Wl,-fini=__kmp_internal_end_fini instead of relying on the linker retaining the bitcode defined symbols.

I think the problem here is that -Wl,-fini without -u works when you don't use LTO, but when you enable it the function is removed and with it the FINI entry in .dynamic. As a layperson I might expect (as the OpenMP writers did) that an explicit -fini flag on the command line is sufficient, and that the linker makes sure LTO doesn't drop the function since it is arguably used.

I can't really comment on this patch though, because I don't know under which circumstances one might use inits or finis that are undefined, and then expect them to be dropped.

MaskRay added a comment.EditedJul 10 2020, 4:22 PM

OK, I think D69885 (lto/init-fini.ll) still makes sense. A bitcode symbol can behave like a regular symbol or an archive symbol.
For the -init case, a bitcode definition should behave more like a regular definition and -init can cause the definition to be emitted.

This patch makes LLD similar to GNU ld: there is no symbol table entry for -init:

cat > a.s <<e
 .globl _init, foo
 _init:
 foo:
   ret
e
as a.s -o a.o
ar rc a.a a.o
as /dev/null -o b.o
ld.bfd -init=foo b.o a.a  # a.a(a.o) not fetched & foo does not exist
ld.bfd b.o a.a  # a.a(a.o) not fetched & foo does not exist

This makes sense because linking in a dropped archive should not affect the symbol table. This intention is not clearly given in the description.

lld/test/ELF/archive-init-fini.s
3 ↗(On Diff #277006)

If you delete _start from init-fini.s, you can add this test into init-fini.s

7 ↗(On Diff #277006)

%t.o

10 ↗(On Diff #277006)

%t.out -> %t

MaskRay retitled this revision from [ELF] Do not force bringing out symbols passed by -init and -fini. to [ELF] Do not leave undefined symbols (specified by -init and -fini) if they are defined in non-fetched archive members.Jul 10 2020, 4:40 PM
ikudrin updated this revision to Diff 277341.Jul 13 2020, 1:26 AM
ikudrin marked 2 inline comments as done.
  • Moved the test into init-fini.s.

Thanks @MaskRay for updating the title! I'll use it for the commit message.

lld/test/ELF/archive-init-fini.s
7 ↗(On Diff #277006)

This and the next comment are not done because init-fini.s uses a different naming scheme.

MaskRay accepted this revision.Jul 13 2020, 8:40 AM

LGTM.

This revision is now accepted and ready to land.Jul 13 2020, 8:40 AM
This revision was automatically updated to reflect the committed changes.