[llvm-dev] Weak symbol/alias semantics

Teresa Johnson via llvm-dev llvm-dev at lists.llvm.org
Fri Jan 13 14:33:30 PST 2017


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170113/5a4976eb/attachment.html>


More information about the llvm-dev mailing list