diff --git a/libc/bionic/libc_init_common.c b/libc/bionic/libc_init_common.c index b6a637923..7fb1246a7 100644 --- a/libc/bionic/libc_init_common.c +++ b/libc/bionic/libc_init_common.c @@ -52,12 +52,19 @@ unsigned int __page_shift = PAGE_SHIFT; int __system_properties_init(void); -void __libc_init_common(uintptr_t *elfdata) +/* Init TLS for the initial thread. Called by the linker _before_ libc is mapped + * in memory. Beware: all writes to libc globals from this function will + * apply to linker-private copies and will not be visible from libc later on. + * + * Note: this function creates a pthread_internal_t for the initial thread and + * stores the pointer in TLS, but does not add it to pthread's gThreadList. This + * has to be done later from libc itself (see __libc_init_common). + * + * This function also stores elfdata argument in a specific TLS slot to be later + * picked up by the libc constructor. + */ +void __libc_init_tls(unsigned** elfdata) { - int argc = *elfdata; - char** argv = (char**)(elfdata + 1); - char** envp = argv + argc + 1; - pthread_attr_t thread_attr; static pthread_internal_t thread; static void* tls_area[BIONIC_TLS_SLOTS]; @@ -72,7 +79,19 @@ void __libc_init_common(uintptr_t *elfdata) _init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom); __init_tls(tls_area, &thread); - /* clear errno - requires TLS area */ + tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata; +} + +void __libc_init_common(uintptr_t *elfdata) +{ + int argc = *elfdata; + char** argv = (char**)(elfdata + 1); + char** envp = argv + argc + 1; + + /* get the initial thread from TLS and add it to gThreadList */ + _pthread_internal_add(__get_thread()); + + /* clear errno */ errno = 0; /* set program name */ diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c index a2c11a9d0..f97961d23 100644 --- a/libc/bionic/libc_init_static.c +++ b/libc/bionic/libc_init_static.c @@ -65,6 +65,11 @@ __noreturn void __libc_init(uintptr_t *elfdata, int argc; char **argv, **envp; + __libc_init_tls(NULL); + + /* get the initial thread from TLS and add it to gThreadList */ + _pthread_internal_add(__get_thread()); + /* Initialize the C runtime environment */ __libc_init_common(elfdata); diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c index fdfe50856..5cad1674b 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -145,7 +145,7 @@ _pthread_internal_remove( pthread_internal_t* thread ) pthread_mutex_unlock(&gThreadListLock); } -static void +__LIBC_ABI_PRIVATE__ void _pthread_internal_add( pthread_internal_t* thread ) { pthread_mutex_lock(&gThreadListLock); @@ -157,7 +157,7 @@ _pthread_internal_add( pthread_internal_t* thread ) pthread_mutex_unlock(&gThreadListLock); } -pthread_internal_t* +__LIBC_ABI_PRIVATE__ pthread_internal_t* __get_thread(void) { void** tls = (void**)__get_tls(); @@ -217,6 +217,7 @@ void __thread_entry(int (*func)(void*), void *arg, void **tls) pthread_exit( (void*)func(arg) ); } +__LIBC_ABI_PRIVATE__ void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base) { if (attr == NULL) { @@ -238,8 +239,6 @@ void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * thread->join_count = 0; thread->cleanup_stack = NULL; - - _pthread_internal_add(thread); } @@ -371,6 +370,8 @@ int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr, _init_thread(thread, tid, (pthread_attr_t*)attr, stack); + _pthread_internal_add(thread); + if (!madestack) thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK; diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index 655b8f341..268cacf6c 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -47,6 +47,8 @@ typedef struct pthread_internal_t } pthread_internal_t; extern void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base); +void _pthread_internal_add( pthread_internal_t* thread ); +pthread_internal_t* __get_thread(void); /* needed by posix-timers.c */ diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h index 008fd2ff7..af19554ec 100644 --- a/libc/private/bionic_tls.h +++ b/libc/private/bionic_tls.h @@ -134,6 +134,9 @@ extern void* __get_tls( void ); /* return the stack base and size, used by our malloc debugger */ extern void* __get_stack_base(int *p_stack_size); +/* Initialize the TLS. */ +extern void __libc_init_tls(unsigned** elfdata); + __END_DECLS #endif /* _SYS_TLS_H */ diff --git a/linker/linker.c b/linker/linker.c index 9805b35e3..6b6282dc8 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -2054,10 +2054,6 @@ static void parse_preloads(const char *path, char *delim) } } -#define ANDROID_TLS_SLOTS BIONIC_TLS_SLOTS - -static void * __tls_area[ANDROID_TLS_SLOTS]; - /* * This code is called after the linker has linked itself and * fixed it's own GOT. It is safe to make references to externs @@ -2076,18 +2072,6 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata) const char *ldpath_env = NULL; const char *ldpreload_env = NULL; - /* Setup a temporary TLS area that is used to get a working - * errno for system calls. - */ - __set_tls(__tls_area); - - pid = getpid(); - -#if TIMING - struct timeval t0, t1; - gettimeofday(&t0, 0); -#endif - /* NOTE: we store the elfdata pointer on a special location * of the temporary TLS area in order to pass it to * the C Library's runtime initializer. @@ -2096,7 +2080,14 @@ static unsigned __linker_init_post_relocation(unsigned **elfdata) * to point to a different location to ensure that no other * shared library constructor can access it. */ - __tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata; + __libc_init_tls(elfdata); + + pid = getpid(); + +#if TIMING + struct timeval t0, t1; + gettimeofday(&t0, 0); +#endif /* Initialize environment functions, and get to the ELF aux vectors table */ vecs = linker_env_init(vecs);