i guess it is related to bug 67548 but it happens without -r now. void foo(void) {} extern void foo_alias(void) __attribute__((weak, alias("foo"))); int bar = 0; extern int bar_alias __attribute__((weak, alias("bar"))); compiled as gcc -shared -fPIC -flto -o foo.so foo.c $ readelf --dyn-sym -W foo.so |grep foo 8: 0000000000000640 6 FUNC GLOBAL DEFAULT 10 foo_alias 9: 0000000000000640 6 FUNC GLOBAL DEFAULT 10 foo $ readelf --dyn-sym -W foo.so |grep bar 4: 00000000002008cc 4 OBJECT GLOBAL DEFAULT 21 bar 6: 00000000002008cc 4 OBJECT GLOBAL DEFAULT 21 bar_alias without -flto i get the expected $ readelf --dyn-sym -W foo.so |grep foo 8: 0000000000000640 7 FUNC WEAK DEFAULT 10 foo_alias 9: 0000000000000640 7 FUNC GLOBAL DEFAULT 10 foo $ readelf --dyn-sym -W foo.so |grep bar 4: 00000000002008cc 4 OBJECT GLOBAL DEFAULT 21 bar 6: 00000000002008cc 4 OBJECT WEAK DEFAULT 21 bar_alias this silently breaks the libc if it's compiled with lto my gcc version is 6.0.0 20160113, tested on x86_64 and aarch64 targets.
hm it happens on gcc-5 too, gcc-49 is ok.
Well, -shared is somewhat similar here.
mine. I wonder why WEAK makes difference here at all when all symbols are interposable with PIC.
The optimization was intentional - dropping the weak bit makes GCC to optimize the references to symbol better (knowing it won't be NULL because the definition is provided). I wonder how this break glibc. What is the difference between weak and non-weak symbols in dynamic linking?
copy pasting from http://www.openwall.com/lists/musl/2016/01/13/2 (this is musl libc, but glibc has the same issue) lto breaks symbol binding for environ, _environ, ___environ. (they should be weak, without that environ in a main binary has different address than in libc.so) libc.so built with -flto: $ readelf --dyn-syms -W libc.so |grep envi 22: 000000000028eb90 8 OBJECT GLOBAL DEFAULT 15 __environ 398: 000000000028eb90 8 OBJECT GLOBAL PROTECTED 15 ___environ 1034: 000000000028eb90 8 OBJECT GLOBAL PROTECTED 15 _environ 1107: 000000000028eb90 8 OBJECT GLOBAL DEFAULT 15 environ libc.so without -flto: $ readelf --dyn-syms -W libc.so |grep envi 22: 000000000028d2d8 8 OBJECT GLOBAL DEFAULT 15 __environ 398: 000000000028d2d8 8 OBJECT WEAK PROTECTED 15 ___environ 1034: 000000000028d2d8 8 OBJECT WEAK PROTECTED 15 _environ 1107: 000000000028d2d8 8 OBJECT WEAK DEFAULT 15 environ
to complete the example here is a test application: #include <stdio.h> #include <stdlib.h> extern char **environ; int main() { printf("&environ: %p, environ: %p, *environ: %p\n", &environ, environ, *environ); clearenv(); // *environ = 0 putenv("TEST=1"); // should change environ printf("&environ: %p, environ: %p, *environ: %p\n", &environ, environ, *environ); } with correct libc.so: $ gcc a.c $ ./a.out &environ: 0x6008b0, environ: 0x7fffb9b0b478, *environ: 0x7fffb9b0d651 &environ: 0x6008b0, environ: 0x600020, *environ: 0x400649 $ readelf --dyn-sym -W ./a.out |grep envi 2: 00000000006008b0 8 OBJECT WEAK DEFAULT 19 _environ 5: 00000000006008b0 8 OBJECT GLOBAL DEFAULT 19 __environ 7: 00000000006008b0 8 OBJECT WEAK DEFAULT 19 environ 8: 00000000006008b0 8 OBJECT WEAK DEFAULT 19 ___environ if libc.so is compiled with -flto: $ gcc a.c $ ./a.out &environ: 0x600850, environ: 0x7fff52af6158, *environ: 0x7fff52af6651 &environ: 0x600850, environ: 0x7fff52af6158, *environ: 0 $ readelf --dyn-sym -W ./a.out |grep envi 5: 0000000000600850 8 OBJECT GLOBAL DEFAULT 19 environ so environ is shared between a.out and libc.so in the beginning (clearenv worked), but the address of the symbol (&environ) is different so changing it in the libc did not have an effect in the main module (putenv failed). this might be an issue in the static or dynamic linker but the difference is observable.
Jan Hubicka, when ld resolves a reference that requires a copy relocation to a weak definition in a shared library, it searches for a strong symbol for which the weak definition is an alias, and replaces the reference with one to the strong symbol. This is necessary to ensure that &weak_alias == &strong_sym at runtime after the copy relocation changes the address of the symbol.
Ok, compiling: int bar = 0; extern int bar_alias __attribute__((weak, alias("bar"))); main() { printf ("%i %i\n",bar,bar_alias); } as a static library leads to no dynamic relocations, but compiling as shared we get bar_alias still declared weak which affects the dynamic linking (because it can be replaced by strong definition which come later in the linking process). So all we need to do is to avoid turning WEAK to non-WEAK for non-hidden symbols when building with PIC?