[llvm-dev] Weak symbol/alias semantics

Xinliang David Li via llvm-dev llvm-dev at lists.llvm.org
Fri Jan 13 15:05:36 PST 2017


'strong_alias' is resolved to the copy of 'f' in weak1.c and it does not
have weak linkage. In other words weak symbol 'f' in weak1.c gets
'promoted' to be non-weak through name 'strong_alias'.  Given the above,
-O0's behavior is more correct. It is also consistent with what GCC does
(both O0 and O2).

David

On Fri, Jan 13, 2017 at 2:33 PM, Teresa Johnson <tejohnson at google.com>
wrote:

> Hi Mehdi, Peter and David (and anyone else who sees this),
>
> I've been playing with some examples to handle the weak symbol cases we
> discussed in IRC earlier this week in the context of D28523. I was going to
> implement the support for turning aliases into copies in order to enable
> performing thinLTOResolveWeakForLinkerGUID on both aliases and aliasees,
> as a first step to being able to drop non-prevailing weak symbols in
> ThinLTO backends.
>
> I was wondering though what happens if we have an alias, which may or may
> not be weak itself, to a non-odr weak symbol that isn't prevailing. In that
> case, do we eventually want references via the alias to go to the
> prevailing copy (in another module), or to the original copy in the alias's
> module? I looked at some examples without ThinLTO, and am a little
> confused. Current (non-ThinLTO) behavior in some cases seems to depend on
> opt level.
>
> Example:
>
> $ cat weak12main.c
> extern void test2();
> int main() {
>   test2();
> }
>
> $ cat weak1.c
> #include <stdio.h>
>
> void weakalias() __attribute__((weak, alias ("f")));
> void strongalias() __attribute__((alias ("f")));
>
> void f () __attribute__ ((weak));
> void f()
> {
>   printf("In weak1.c:f\n");
> }
> void test1() {
>   printf("Call f() from weak1.c:\n");
>   f();
>   printf("Call weakalias() from weak1.c:\n");
>   weakalias();
>   printf("Call strongalias() from weak1.c:\n");
>   strongalias();
> }
>
> $ cat weak2.c
> #include <stdio.h>
>
> void f () __attribute__ ((weak));
> void f()
> {
>   printf("In weak2.c:f\n");
> }
> extern void test1();
> void test2()
> {
>   test1();
>   printf("Call f() from weak2.c\n");
>   f();
> }
>
> If I link weak1.c before weak2.c, nothing is surprising (we always invoke
> weak1.c:f at both -O0 and -O2):
>
> $ clang weak12main.c weak1.c weak2.c -O0
> $ a.out
> Call f() from weak1.c:
> In weak1.c:f
> Call weakalias() from weak1.c:
> In weak1.c:f
> Call strongalias() from weak1.c:
> In weak1.c:f
> Call f() from weak2.c
> In weak1.c:f
>
> $ clang weak12main.c weak1.c weak2.c -O2
> $ a.out
> Call f() from weak1.c:
> In weak1.c:f
> Call weakalias() from weak1.c:
> In weak1.c:f
> Call strongalias() from weak1.c:
> In weak1.c:f
> Call f() from weak2.c
> In weak1.c:f
>
> If I instead link weak2.c first, so it's copy of f() is prevailing, I
> still get weak1.c:f for the call via weakalias() (both opt levels), and for
> strongalias() when building at -O0. At -O2 the compiler replaces the call
> to strongalias() with a call to f(), so it get's the weak2 copy in that
> case.
>
> $ clang weak12main.c weak2.c weak1.c -O2
> $ a.out
> Call f() from weak1.c:
> In weak2.c:f
> Call weakalias() from weak1.c:
> In weak1.c:f
> Call strongalias() from weak1.c:
> In weak2.c:f
> Call f() from weak2.c
> In weak2.c:f
>
> $ clang weak12main.c weak2.c weak1.c -O0
> $ a.out
> Call f() from weak1.c:
> In weak2.c:f
> Call weakalias() from weak1.c:
> In weak1.c:f
> Call strongalias() from weak1.c:
> In weak1.c:f
> Call f() from weak2.c
> In weak2.c:f
>
> I'm wondering what the expected/correct behavior is? Depending on what is
> correct, we need to handle this differently in ThinLTO mode. Let's say
> weak1.c's copy of f() is not prevailing and I am going to drop it (it needs
> to be removed completely, not turned into available_externally to ensure it
> isn't inlined since weak isInterposable). If we want the aliases in weak1.c
> to reference the original version, then copying is correct (e.g. weakalias
> and strong alias would each become a copy of weak1.c's f()). If we however
> want them to resolve to the prevailing copy of f(), then we need to turn
> the aliases into declarations (external linkage in the case of strongalias
> and external weak in the case of weakalias?).
>
> I also tried the case where f() was in a comdat, because I also need to
> handle that case in ThinLTO (when f() is not prevailing, drop it from the
> comdat and remove the comdat from that module). Interestingly, in this case
> when weak2.c is prevailing, I get the following warning when linking and
> get a seg fault at runtime:
>
> weak1.o:weak1.o:function test1: warning: relocation refers to discarded
> section
>
> Presumably the aliases still refer to the copy in weak1.c, which is in the
> comdat that gets dropped by the linker. So is it not legal to have an alias
> to a weak symbol in a comdat (i.e. alias from outside the comdat)? We don't
> complain in the compiler.
>
> Thanks,
> Teresa
> --
> Teresa Johnson |  Software Engineer |  tejohnson at google.com |
> 408-460-2413 <(408)%20460-2413>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170113/8f6b1dac/attachment.html>


More information about the llvm-dev mailing list