This is an archive of the discontinued LLVM Phabricator instance.

[LLD][ELF] restore behaviour of __real_foo being a weak reference to a lazy foo
AbandonedPublic

Authored by bd1976llvm on Oct 11 2022, 6:38 PM.

Details

Summary

A use-case we have is to be able to supply a __wrap_foo function and a --wrap=foo command line argument to the linker but for these to only have an effect if foo is included in the link. If foo is not included in the link then a reference to __real_foo should be considered a weak reference.

This was the behaviour previous to https://github.com/llvm/llvm-project/commit/8b01b638d0145473d27a0dd99ded48cc5a8b85a1.

Restore this behaviour.

Diff Detail

Event Timeline

bd1976llvm created this revision.Oct 11 2022, 6:38 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 11 2022, 6:38 PM
bd1976llvm requested review of this revision.Oct 11 2022, 6:38 PM
bd1976llvm edited the summary of this revision. (Show Details)
bd1976llvm retitled this revision from [LLD][ELF] restore behaviour of __real_foo being a weak_reference_to_a_lazy_foo to [LLD][ELF] restore behaviour of __real_foo being a weak reference to a lazy foo.Oct 11 2022, 6:53 PM
bd1976llvm edited the summary of this revision. (Show Details)Oct 12 2022, 9:08 AM

Improve testing and add tests to show that symbol foo is considered referenced by LLD even if all references are redirected by --wrap foo. This property means that a __wrap_foo function that contains calls to __real_foo will not be called if foo is not included in the link.

MaskRay added a comment.EditedOct 12 2022, 4:40 PM

(--wrap is so complex that I can't come up with a list of rules to follow. I can only make sense by inspecting test output difference.)

For wrap-extract-real.s, I don't think the new behavior improves semantics.

ld.lld %t/a.o --wrap foo  # error: undefined symbol: __real_foo
ld.lld %t/a.o --start-lib %t/b.o --end-lib --wrap foo  # ok, even if %t/b.o is not extracted. This is weird

Generally, if an archive member is not extracted, we expect that there is no symbol resolution difference.

lld/test/ELF/wrap-extract-real.s
4

# RUN: rm -rf %t && split-file %s %t && cd %t so that you can omit %t/ below

7

To make better use of the test, use an output and dump the full symbol table with llvm-readelf -s.

9
lld/test/ELF/wrap-extract-unreferenced-orig.s
1

The change does not affect the behavior of this test. What does this test check?

9

Two -o?

(--wrap is so complex that I can't come up with a list of rules to follow. I can only make sense by inspecting test output difference.)

For wrap-extract-real.s, I don't think the new behavior improves semantics.

ld.lld %t/a.o --wrap foo  # error: undefined symbol: __real_foo
ld.lld %t/a.o --start-lib %t/b.o --end-lib --wrap foo  # ok, even if %t/b.o is not extracted. This is weird

Generally, if an archive member is not extracted, we expect that there is no symbol resolution difference.

Thanks for the comments. I agree that the semantics are weird with this change in its current form. This is because I was trying to make as small a change as possible (because --wrap is hard I find!). We could improve this change so the "ld.lld %t/a.o --wrap foo" case is ok as well. However, I have discovered that:

  1. We have a case where someone is referencing __real_xxx outside of __wrap_xxx (I wasn't able to find any documentation to state that this is disallowed and it seems useful) which means that this change (and LLD behaviour previous to https://github.com/llvm/llvm-project/commit/8b01b638d0145473d27a0dd99ded48cc5a8b85a1) leads to a reference patched to zero which could be a bug unless users are aware that __real_xxx references are treated as weak (easy to get wrong).
  1. We can change the implementation for our library that inspired this so that we no longer have the same requirements and would be happy with the ld.bfd behaviour of __real_xxx references extracting xxx from an archive.

For those reasons I am going to abandon this revision.

bd1976llvm added inline comments.Oct 13 2022, 10:51 AM
lld/test/ELF/wrap-extract-unreferenced-orig.s
1

This is testing that lld pulls in a definition of foo from an archive even if there are no references to foo after wrapping (there is no use of __real_foo). With that behaviour it doesn't matter that __real_foo is patched to zero if foo is not extracted from an archive (it's still lazy) because __wrap_foo must be unused. Obviously, this isn't that useful if __real_foo can be used outside of __wrap_foo though....