parlib: Fix dlopen() with -rdynamic
Part 3 of trying to fix shared objects, following up on commit c77d5ade84b7
("parlib: Fix fake parlib detection for dlopen() (XCC)").
If we use -rdynamic, all symbols from the binary (e.g. hello.c) will
override functions in the .so. For instance, __in_fake_parlib() and
vcore_lib_init() will be from the binary, not the .so, even when we're
running the library's ctors.
The fix is relatively simple: __in_fake_parlib() is a static inline, which
won't give the opportunity for the .so to link against a global version,
since there is no global version.
For the ctors, we actually could leave vcore_lib_init() as a global ctor,
since it can safely be called multiple times. But that's a little sloppy
and confusing - I wondered for a little while why vcore_lib_init() ran from
hello, while uthread_lib_init() was run from within the .so. static vs
global. We still need the guts vcore_lib_init() to be in a header for
uthread.c, so the sanest thing was to just split it up.
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/user/parlib/alarm.c b/user/parlib/alarm.c
index 54eaad4..b11accd 100644
--- a/user/parlib/alarm.c
+++ b/user/parlib/alarm.c
@@ -147,7 +147,7 @@
global_tchain.timerfd = -42;
}
-static void __attribute__((constructor)) init_alarm_service(void)
+static void __attribute__((constructor)) alarm_service_ctor(void)
{
int ctlfd, timerfd, alarmid;
struct event_queue *ev_q;
diff --git a/user/parlib/include/parlib/vcore.h b/user/parlib/include/parlib/vcore.h
index 6e8f2ef..242902e 100644
--- a/user/parlib/include/parlib/vcore.h
+++ b/user/parlib/include/parlib/vcore.h
@@ -40,8 +40,9 @@
static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid);
static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid);
static inline void cpu_relax_any(void);
+static inline bool __in_fake_parlib(void);
+
void vcore_lib_init(void);
-bool __in_fake_parlib(void);
void vcore_change_to_m(void);
void vcore_request_more(long nr_new_vcores);
void vcore_request_total(long nr_vcores_wanted);
@@ -193,6 +194,23 @@
return cpu_relax_vc(vcore_id());
}
+/* Shared libraries also contain parlib. That'll be true until we start making
+ * parlib a .so, which has some TLS implications (and maybe others). The real
+ * parlib is the one in the program binary, not the shared libraries. This
+ * detection works because all shared libs, both the -l and the dlopens, are
+ * mapped above the BRK.
+ *
+ * Previously, we tried using weak symbols, specifically _start or _end, but be
+ * careful. If you pass e.g. _start or _end to a function or inline asm, the
+ * program binary will do something slightly different, which may make the
+ * shared library load different values. */
+static inline bool __in_fake_parlib(void)
+{
+ static char dummy;
+
+ return (uintptr_t)&dummy > BRK_START;
+}
+
#ifndef __PIC__
#define begin_safe_access_tls_vars()
diff --git a/user/parlib/panic.c b/user/parlib/panic.c
index dc796f5..44e992e 100644
--- a/user/parlib/panic.c
+++ b/user/parlib/panic.c
@@ -5,7 +5,7 @@
#include <stdarg.h>
#include <stdlib.h>
-static void __attribute__((constructor)) parlib_stdio_init(void)
+static void __attribute__((constructor)) parlib_stdio_ctor(void)
{
if (__in_fake_parlib())
return;
diff --git a/user/parlib/uthread.c b/user/parlib/uthread.c
index 5f5ec9e..85f7ea0 100644
--- a/user/parlib/uthread.c
+++ b/user/parlib/uthread.c
@@ -159,13 +159,13 @@
return current_uthread->err_str;
}
-static void __attribute__((constructor)) uthread_lib_init(void)
+static void __attribute__((constructor)) uthread_lib_ctor(void)
{
/* Surprise! Parlib's ctors also run in shared objects. We can't have
* multiple versions of parlib (with multiple data structures). */
if (__in_fake_parlib())
return;
- /* Need to make sure the vcore_lib_init() ctor runs first */
+ /* Need to make sure vcore_lib_init() runs first */
vcore_lib_init();
/* Instead of relying on ctors for the specific 2LS, we make sure they are
* called next. They will call uthread_2ls_init().
diff --git a/user/parlib/vcore.c b/user/parlib/vcore.c
index 3a29c65..32c89e3 100644
--- a/user/parlib/vcore.c
+++ b/user/parlib/vcore.c
@@ -37,28 +37,6 @@
}
void vcore_entry(void) __attribute__((weak, alias ("__vcore_entry")));
-static void __fake_start(void)
-{
-}
-void _start(void) __attribute__((weak, alias ("__fake_start")));
-
-/* Shared libraries also contain parlib. That'll be true until we start making
- * parlib a .so, which has some TLS implications (and maybe others). The real
- * parlib is the one in the program binary, not the shared libraries. This
- * detection works because all shared libs, both the -l and the dlopens, are
- * mapped above the BRK.
- *
- * Previously, we tried using weak symbols, specifically _start or _end, but be
- * careful. If you pass e.g. _start or _end to a function or inline asm, the
- * program binary will do something slightly different, which may make the
- * shared library load different values. */
-bool __in_fake_parlib(void)
-{
- static char dummy;
-
- return (uintptr_t)&dummy > BRK_START;
-}
-
/* TODO: probably don't want to dealloc. Considering caching */
static void free_transition_tls(int id)
{
@@ -192,10 +170,14 @@
* program. */
}
-void __attribute__((constructor)) vcore_lib_init(void)
+/* We need to separate the guts of vcore_lib_ctor() into a separate function,
+ * since the uthread ctor depends on this ctor running first.
+ *
+ * Also note that if you make a global ctor (not static, like this used to be),
+ * any shared objects that you load when the binary is built with -rdynamic will
+ * run the global ctor from the binary, not the one from the .so. */
+void vcore_lib_init(void)
{
- if (__in_fake_parlib())
- return;
/* Note this is racy, but okay. The first time through, we are _S.
* Also, this is the "lowest" level constructor for now, so we don't need
* to call any other init functions after our run_once() call. This may
@@ -209,6 +191,13 @@
vcore_libc_init();
}
+static void __attribute__((constructor)) vcore_lib_ctor(void)
+{
+ if (__in_fake_parlib())
+ return;
+ vcore_lib_init();
+}
+
/* Helper functions used to reenter at the top of a vcore's stack for an
* arbitrary function */
static void __attribute__((noinline, noreturn))
diff --git a/user/parlib/vcore_tick.c b/user/parlib/vcore_tick.c
index fcd9e1d..7df2e5f 100644
--- a/user/parlib/vcore_tick.c
+++ b/user/parlib/vcore_tick.c
@@ -33,7 +33,7 @@
static struct vcore_tick *__vc_ticks;
-static void __attribute__((constructor)) vcore_tick_lib_init(void)
+static void __attribute__((constructor)) vcore_tick_lib_ctor(void)
{
if (__in_fake_parlib())
return;