remove undef weak refs to init/fini array symbols in libc.so
authorRich Felker <dalias@aerifal.cx>
Fri, 20 Nov 2015 01:28:08 +0000 (20:28 -0500)
committerRich Felker <dalias@aerifal.cx>
Fri, 20 Nov 2015 03:10:55 +0000 (22:10 -0500)
commit ad1cd43a86645ba2d4f7c8747240452a349d6bc1 eliminated
preprocessor-level omission of references to the init/fini array
symbols from object files going into libc.so. the references are weak,
and the intent was that the linker would resolve them to zero in
libc.so, but instead it leaves undefined references that could be
satisfied at runtime. normally these references would be harmless,
since the code using them does not even get executed, but some older
binutils versions produce a linking error: when linking a program
against libc.so, ld first tries to use the hidden init/fini array
symbols produced by the linker script to satisfy the references in
libc.so, then produces an error because the definitions are hidden.

ideally ld would have already provided definitions of these symbols
when linking libc.so, but the linker script for -shared omits them.

to avoid this situation, the dynamic linker now provides its own dummy
definitions of the init/fini array symbols for libc.so. since they are
hidden, everything binds at ld time and no references remain in the
dynamic symbol table. with modern binutils and --gc-sections, both
the dummy empty array objects and the code referencing them get
dropped at link time, anyway.

the _init and _fini symbols are also switched back to using weak
definitions rather than weak references since the latter behave
somewhat problematically in general, and the weak definition approach
was known to work well.

src/env/__libc_start_main.c
src/exit/exit.c
src/internal/vis.h
src/ldso/dynlink.c

index 7ffada0bae1837a971a183108c43804235d75092..5c79be28f0b5c8205a53ad1f23510b57da9ca7d4 100644 (file)
@@ -8,9 +8,11 @@
 
 void __init_tls(size_t *);
 
-extern void _init() __attribute__((weak));
-extern void (*const __init_array_start)() __attribute__((weak));
-extern void (*const __init_array_end)() __attribute__((weak));
+static void dummy(void) {}
+weak_alias(dummy, _init);
+
+__attribute__((__weak__, __visibility__("hidden")))
+extern void (*const __init_array_start)(void), (*const __init_array_end)(void);
 
 static void dummy1(void *p) {}
 weak_alias(dummy1, __init_ssp);
@@ -53,7 +55,7 @@ void __init_libc(char **envp, char *pn)
 
 static void libc_start_init(void)
 {
-       if (_init) _init();
+       _init();
        uintptr_t a = (uintptr_t)&__init_array_start;
        for (; a<(uintptr_t)&__init_array_end; a+=sizeof(void(*)()))
                (*(void (**)())a)();
index b391f33871a86473dc8acd3228b2c5f1a1e0a0db..bf7835a15cd2d3ecf9d7d7c7e8e1dc25a62d2806 100644 (file)
@@ -10,17 +10,17 @@ static void dummy()
  * as a consequence of linking either __toread.c or __towrite.c. */
 weak_alias(dummy, __funcs_on_exit);
 weak_alias(dummy, __stdio_exit);
+weak_alias(dummy, _fini);
 
-extern void _fini() __attribute__((weak));
-extern void (*const __fini_array_start)() __attribute__((weak));
-extern void (*const __fini_array_end)() __attribute__((weak));
+__attribute__((__weak__, __visibility__("hidden")))
+extern void (*const __fini_array_start)(void), (*const __fini_array_end)(void);
 
 static void libc_exit_fini(void)
 {
        uintptr_t a = (uintptr_t)&__fini_array_end;
        for (; a>(uintptr_t)&__fini_array_start; a-=sizeof(void(*)()))
                (*(void (**)())(a-sizeof(void(*)())))();
-       if (_fini) _fini();
+       _fini();
 }
 
 weak_alias(libc_exit_fini, __libc_exit_fini);
index 02bfbda88e5b456b8a573c540764b27e6d6f397d..8414179e6054be516cd678e3f867642535678161 100644 (file)
@@ -8,8 +8,7 @@
 
 /* Conceptually, all symbols should be protected, but some toolchains
  * fail to support copy relocations for protected data, so exclude all
- * exported data symbols. Also omit visibility for possibly-undefined
- * weak references. */
+ * exported data symbols. */
 
 __attribute__((__visibility__("default")))
 extern struct _IO_FILE *const stdin, *const stdout, *const stderr;
@@ -23,10 +22,6 @@ extern long timezone, __timezone;
 __attribute__((__visibility__("default")))
 extern char *optarg, **environ, **__environ, *tzname[2], *__tzname[2], *__progname, *__progname_full;
 
-__attribute__((__visibility__("default")))
-extern void (*const __init_array_start)(), (*const __init_array_end)(),
-       (*const __fini_array_start)(), (*const __fini_array_end)();
-
 #pragma GCC visibility push(protected)
 
 #endif
index 6495aeeac061bc68449ec07fd9edca2b92c66ab5..4648e9ac33e669c2dd1df9594ab5d0385adb9485 100644 (file)
@@ -134,6 +134,15 @@ static struct fdpic_dummy_loadmap app_dummy_loadmap;
 
 struct debug *_dl_debug_addr = &debug;
 
+__attribute__((__visibility__("hidden")))
+void (*const __init_array_start)(void)=0, (*const __fini_array_start)(void)=0;
+
+__attribute__((__visibility__("hidden")))
+extern void (*const __init_array_end)(void), (*const __fini_array_end)(void);
+
+weak_alias(__init_array_start, __init_array_end);
+weak_alias(__fini_array_start, __fini_array_end);
+
 static int dl_strcmp(const char *l, const char *r)
 {
        for (; *l==*r && *l; l++, r++);