Fix __get_tls() in static C library to use kernel helpers.

This is needed to fix gdbserver's handling of threaded programs,
among other things.

Change-Id: I823387c602cef9891532da946a01db14be780ab0
This commit is contained in:
David 'Digit' Turner 2010-08-27 08:19:19 -07:00
parent 22f1e3d4fa
commit 6a51defa03
3 changed files with 74 additions and 15 deletions

View file

@ -64,7 +64,6 @@ libc_common_src_files := \
unistd/sleep.c \ unistd/sleep.c \
unistd/statfs.c \ unistd/statfs.c \
unistd/strsignal.c \ unistd/strsignal.c \
unistd/sysconf.c \
unistd/syslog.c \ unistd/syslog.c \
unistd/system.c \ unistd/system.c \
unistd/tcgetpgrp.c \ unistd/tcgetpgrp.c \
@ -245,7 +244,6 @@ libc_common_src_files := \
tzcode/localtime.c \ tzcode/localtime.c \
tzcode/strftime.c \ tzcode/strftime.c \
tzcode/strptime.c \ tzcode/strptime.c \
bionic/__errno.c \
bionic/__set_errno.c \ bionic/__set_errno.c \
bionic/_rand48.c \ bionic/_rand48.c \
bionic/cpuacct.c \ bionic/cpuacct.c \
@ -314,6 +312,23 @@ libc_common_src_files := \
regex/regexec.c \ regex/regexec.c \
regex/regfree.c \ regex/regfree.c \
# The following files are common, but must be compiled
# with different C flags when building a static C library.
#
# The reason for this is the implementation of __get_tls()
# that will differ between the shared and static versions
# of the library.
#
# See comments in private/bionic_tls.h for more details.
#
# NOTE: bionic/pthread.c is added later to this list
# because it needs special handling on ARM, see
# below.
#
libc_static_common_src_files := \
unistd/sysconf.c \
bionic/__errno.c \
# Architecture specific source files go here # Architecture specific source files go here
# ========================================================= # =========================================================
ifeq ($(TARGET_ARCH),arm) ifeq ($(TARGET_ARCH),arm)
@ -348,11 +363,13 @@ libc_common_src_files += \
# can set breakpoints in them without messing # can set breakpoints in them without messing
# up any thumb code. # up any thumb code.
libc_common_src_files += \ libc_common_src_files += \
bionic/pthread.c.arm \
bionic/pthread-rwlocks.c.arm \ bionic/pthread-rwlocks.c.arm \
bionic/pthread-timers.c.arm \ bionic/pthread-timers.c.arm \
bionic/ptrace.c.arm bionic/ptrace.c.arm
libc_static_common_src_files += \
bionic/pthread.c.arm \
# these are used by the static and dynamic versions of the libc # these are used by the static and dynamic versions of the libc
# respectively # respectively
libc_arch_static_src_files := \ libc_arch_static_src_files := \
@ -383,11 +400,13 @@ libc_common_src_files += \
arch-x86/string/strcmp_wrapper.S \ arch-x86/string/strcmp_wrapper.S \
arch-x86/string/strncmp_wrapper.S \ arch-x86/string/strncmp_wrapper.S \
arch-x86/string/strlen.S \ arch-x86/string/strlen.S \
bionic/pthread.c \
bionic/pthread-rwlocks.c \ bionic/pthread-rwlocks.c \
bionic/pthread-timers.c \ bionic/pthread-timers.c \
bionic/ptrace.c bionic/ptrace.c
libc_static_common_src_files += \
bionic/pthread.c \
# this is needed for static versions of libc # this is needed for static versions of libc
libc_arch_static_src_files := \ libc_arch_static_src_files := \
arch-x86/bionic/dl_iterate_phdr_static.c arch-x86/bionic/dl_iterate_phdr_static.c
@ -420,11 +439,14 @@ libc_common_src_files += \
string/strncmp.c \ string/strncmp.c \
string/memcmp.c \ string/memcmp.c \
string/strlen.c \ string/strlen.c \
bionic/pthread.c \
bionic/pthread-rwlocks.c \ bionic/pthread-rwlocks.c \
bionic/pthread-timers.c \ bionic/pthread-timers.c \
bionic/ptrace.c \ bionic/ptrace.c \
unistd/socketcalls.c unistd/socketcalls.c
libc_static_common_src_files += \
bionic/pthread.c \
endif # sh endif # sh
endif # !x86 endif # !x86
@ -584,10 +606,12 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
$(libc_arch_static_src_files) \ $(libc_arch_static_src_files) \
$(libc_static_common_src_files) \
bionic/libc_init_static.c bionic/libc_init_static.c
LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_CFLAGS := $(libc_common_cflags) LOCAL_CFLAGS := $(libc_common_cflags) \
-DLIBC_STATIC
LOCAL_MODULE := libc_nomalloc LOCAL_MODULE := libc_nomalloc
LOCAL_WHOLE_STATIC_LIBRARIES := libc_common LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
@ -603,6 +627,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
$(libc_arch_static_src_files) \ $(libc_arch_static_src_files) \
$(libc_static_common_src_files) \
bionic/dlmalloc.c \ bionic/dlmalloc.c \
bionic/malloc_debug_common.c \ bionic/malloc_debug_common.c \
bionic/libc_init_static.c bionic/libc_init_static.c
@ -627,6 +652,7 @@ LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
$(libc_arch_dynamic_src_files) \ $(libc_arch_dynamic_src_files) \
$(libc_static_common_src_files) \
bionic/dlmalloc.c \ bionic/dlmalloc.c \
bionic/malloc_debug_common.c \ bionic/malloc_debug_common.c \
bionic/libc_init_dynamic.c bionic/libc_init_dynamic.c

View file

@ -73,6 +73,13 @@ Differences between current and Android 2.2:
- <dlfcn.h>: fixed dlopen() implementation to support dlopen(NULL, ...). - <dlfcn.h>: fixed dlopen() implementation to support dlopen(NULL, ...).
This allows one to look at the dynamic symbols exported by an executable. This allows one to look at the dynamic symbols exported by an executable.
- <private/bionic_tls.h>: use kernel helper functions for static versions
of the C library. This is necessary because we don't know where the corresponding
machine code is going to run, and the optimization for __get_tls() might
not match the features of the target device where we run a static executable
linked to the C library. This fixes one of the bug that explains why gdbserver
didn't work well with threads.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Differences between Android 2.2. and Android 2.1: Differences between Android 2.2. and Android 2.1:

View file

@ -88,22 +88,48 @@ extern int __set_tls(void *ptr);
/* get the TLS */ /* get the TLS */
#ifdef __arm__ #ifdef __arm__
/* Linux kernel helpers for its TLS implementation */ /* The standard way to get the TLS is to call a kernel helper
/* For performance reasons, avoid calling the kernel helper * function (i.e. a function provided at a fixed address in a
* "magic page" mapped in all user-space address spaces ), which
* contains the most appropriate code path for the target device.
*
* However, for performance reasons, we're going to use our own
* machine code for the system's C shared library.
*
* We cannot use this optimization in the static version of the
* C library, because we don't know where the corresponding code
* is going to run.
*/
# ifdef LIBC_STATIC
/* Use the kernel helper in static C library. */
typedef volatile void* (__kernel_get_tls_t)(void);
# define __get_tls() (*(__kernel_get_tls_t *)0xffff0fe0)()
# else /* !LIBC_STATIC */
/* Use optimized code path.
* Note that HAVE_ARM_TLS_REGISTER is build-specific * Note that HAVE_ARM_TLS_REGISTER is build-specific
* (it must match your kernel configuration) * (it must match your kernel configuration)
*/ */
# ifdef HAVE_ARM_TLS_REGISTER # ifdef HAVE_ARM_TLS_REGISTER
# define __get_tls() \ /* We can read the address directly from a coprocessor
* register, which avoids touching the data cache
* completely.
*/
# define __get_tls() \
({ register unsigned int __val asm("r0"); \ ({ register unsigned int __val asm("r0"); \
asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \ asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \
(volatile void*)__val; }) (volatile void*)__val; })
# else /* !HAVE_ARM_TLS_REGISTER */ # else /* !HAVE_ARM_TLS_REGISTER */
# define __get_tls() ( *((volatile void **) 0xffff0ff0) ) /* The kernel provides the address of the TLS at a fixed
# endif * address of the magic page too.
#else */
# define __get_tls() ( *((volatile void **) 0xffff0ff0) )
# endif
# endif /* !LIBC_STATIC */
#else /* !ARM */
extern void* __get_tls( void ); extern void* __get_tls( void );
#endif #endif /* !ARM */
/* 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);