Initialize TLS before any application code is run.
Since e19d702b8e
, dlsym and friends use recursive mutexes that
require the current thread id, which is not available before the libc
constructor. This prevents us from using dlsym() in .preinit_array.
This change moves TLS initialization from libc constructor to the earliest
possible point - immediately after linker itself is relocated. As a result,
pthread_internal_t for the initial thread is available from the start.
As a bonus, values stored in TLS in .preinit_array are not lost when libc is
initialized.
Change-Id: Iee5a710ee000173bff63e924adeb4a4c600c1e2d
This commit is contained in:
@@ -52,12 +52,19 @@ unsigned int __page_shift = PAGE_SHIFT;
|
|||||||
|
|
||||||
int __system_properties_init(void);
|
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;
|
pthread_attr_t thread_attr;
|
||||||
static pthread_internal_t thread;
|
static pthread_internal_t thread;
|
||||||
static void* tls_area[BIONIC_TLS_SLOTS];
|
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_thread(&thread, gettid(), &thread_attr, (void*)stackbottom);
|
||||||
__init_tls(tls_area, &thread);
|
__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;
|
errno = 0;
|
||||||
|
|
||||||
/* set program name */
|
/* set program name */
|
||||||
|
@@ -65,6 +65,11 @@ __noreturn void __libc_init(uintptr_t *elfdata,
|
|||||||
int argc;
|
int argc;
|
||||||
char **argv, **envp;
|
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 */
|
/* Initialize the C runtime environment */
|
||||||
__libc_init_common(elfdata);
|
__libc_init_common(elfdata);
|
||||||
|
|
||||||
|
@@ -145,7 +145,7 @@ _pthread_internal_remove( pthread_internal_t* thread )
|
|||||||
pthread_mutex_unlock(&gThreadListLock);
|
pthread_mutex_unlock(&gThreadListLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
__LIBC_ABI_PRIVATE__ void
|
||||||
_pthread_internal_add( pthread_internal_t* thread )
|
_pthread_internal_add( pthread_internal_t* thread )
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&gThreadListLock);
|
pthread_mutex_lock(&gThreadListLock);
|
||||||
@@ -157,7 +157,7 @@ _pthread_internal_add( pthread_internal_t* thread )
|
|||||||
pthread_mutex_unlock(&gThreadListLock);
|
pthread_mutex_unlock(&gThreadListLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_internal_t*
|
__LIBC_ABI_PRIVATE__ pthread_internal_t*
|
||||||
__get_thread(void)
|
__get_thread(void)
|
||||||
{
|
{
|
||||||
void** tls = (void**)__get_tls();
|
void** tls = (void**)__get_tls();
|
||||||
@@ -217,6 +217,7 @@ void __thread_entry(int (*func)(void*), void *arg, void **tls)
|
|||||||
pthread_exit( (void*)func(arg) );
|
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)
|
void _init_thread(pthread_internal_t * thread, pid_t kernel_id, pthread_attr_t * attr, void * stack_base)
|
||||||
{
|
{
|
||||||
if (attr == NULL) {
|
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->join_count = 0;
|
||||||
|
|
||||||
thread->cleanup_stack = NULL;
|
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);
|
_init_thread(thread, tid, (pthread_attr_t*)attr, stack);
|
||||||
|
|
||||||
|
_pthread_internal_add(thread);
|
||||||
|
|
||||||
if (!madestack)
|
if (!madestack)
|
||||||
thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK;
|
thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_STACK;
|
||||||
|
|
||||||
|
@@ -47,6 +47,8 @@ typedef struct pthread_internal_t
|
|||||||
} 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);
|
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 */
|
/* needed by posix-timers.c */
|
||||||
|
|
||||||
|
@@ -134,6 +134,9 @@ extern void* __get_tls( void );
|
|||||||
/* return the stack base and size, used by our malloc debugger */
|
/* return the stack base and size, used by our malloc debugger */
|
||||||
extern void* __get_stack_base(int *p_stack_size);
|
extern void* __get_stack_base(int *p_stack_size);
|
||||||
|
|
||||||
|
/* Initialize the TLS. */
|
||||||
|
extern void __libc_init_tls(unsigned** elfdata);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif /* _SYS_TLS_H */
|
#endif /* _SYS_TLS_H */
|
||||||
|
@@ -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
|
* This code is called after the linker has linked itself and
|
||||||
* fixed it's own GOT. It is safe to make references to externs
|
* 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 *ldpath_env = NULL;
|
||||||
const char *ldpreload_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
|
/* NOTE: we store the elfdata pointer on a special location
|
||||||
* of the temporary TLS area in order to pass it to
|
* of the temporary TLS area in order to pass it to
|
||||||
* the C Library's runtime initializer.
|
* 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
|
* to point to a different location to ensure that no other
|
||||||
* shared library constructor can access it.
|
* 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 */
|
/* Initialize environment functions, and get to the ELF aux vectors table */
|
||||||
vecs = linker_env_init(vecs);
|
vecs = linker_env_init(vecs);
|
||||||
|
Reference in New Issue
Block a user