From 03eabfe65e1e2c36f4d26c78a730fa19a3bdada3 Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Thu, 28 May 2009 15:54:03 +0200 Subject: Fix the C library initialization to avoid calling static C++ constructors twice. The problem was due to the fact that, in the case of dynamic executables, the dynamic linker calls the DT_PREINIT_ARRAY, DT_INIT and DT_INIT_ARRAY constructors when loading shared libraries and dynamic executables, *before* calling the executable's entry point (i.e. arch-$ARCH/bionic/crtbegin_dynamic.c) which in turns call __libc_init() in libc.so, as defined by bionic/libc_init_dynamic.c The latter did call these constructors array again, mistakenly. The patch also updates the documentation of many related functions. Also adds a new section to linker/README.TXT explaining restrictions on C library usage. The patch has been tested on a Dream for stability issues with proprietary blobs: - H264 decoding works - Camera + Video recording works - GPS works - Sensors work The tests in system/extra/tests/bionic/libc/common/test_static_cpp_mutex.cpp has been run and shows the static C++ constructor being called only once. --- linker/README.TXT | 43 +++++++++++++++++++++++++++++++++++++++++++ linker/linker.c | 6 +++--- 2 files changed, 46 insertions(+), 3 deletions(-) (limited to 'linker') diff --git a/linker/README.TXT b/linker/README.TXT index 4fff14e..0be9be4 100644 --- a/linker/README.TXT +++ b/linker/README.TXT @@ -112,3 +112,46 @@ On x86, the lists of constructors and destructors are placed in special sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions are in charge of calling them explicitely. + +C Library Usage Restrictions: +----------------------------- + +The dynamic linker executable (/system/bin/linker) is built using the +static version of the C library (libc.a), in order to use various functions +and system calls provided by it. + +However, it will normally, at runtime, map the shared library version +of the C library (/system/lib/libc.so) as well in the process' address +space. This means that: + +- any global variable defined by the C library will appear twice in + the process address space, at different addresses. + +- some functions will be duplicated too, though those that refer to + global variables will refer to distinct addresses. + +This can lead to subtle conflicts, typically for process-specific data that +is managed through the kernel. A good example is the handling of the +end of the data segment, which is normally done through the 'sbrk' or +'brk' system call by the malloc implementation. + +If two similar, but distinct, malloc implementations run at the same time, +and if each one thinks it exclusively manages some process settings, hideous +corruption or crashes may occur. + +For this very reason, THE DYNAMIC LINKER CANNOT USE malloc()/free() ! +That's why it is linked to a special version of the C library that will +abort when any of these functions (or calloc()/realloc()) is called. + +Moreover, it cannot use any C library feature that could use these +indirectly. Experience as shown that this meant: + +- avoiding any FILE* - related stdio function (fopen, fread, fprintf, etc...) +- avoiding snprintf() with any floating-point formatter ("%f", "%g") + +There are probably other cases that haven't been discovered yet, so the +code needs to be very frugal in its use of the C library. + +This also explains why the linker's tracing macros are all disabled by +default. Enabling them sometimes creates problems, depending on the process +being loaded, so they should be considered an experimental feature for now. diff --git a/linker/linker.c b/linker/linker.c index e398f82..e7d5ab4 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -44,7 +44,7 @@ #include /* special private C library header - see Android.mk */ -#include +#include #include "linker.h" #include "linker_debug.h" @@ -1691,6 +1691,7 @@ int main(int argc, char **argv) #define ANDROID_TLS_SLOTS BIONIC_TLS_SLOTS static void * __tls_area[ANDROID_TLS_SLOTS]; +static pthread_internal_t __main_thread; unsigned __linker_init(unsigned **elfdata) { @@ -1709,8 +1710,7 @@ unsigned __linker_init(unsigned **elfdata) gettimeofday(&t0, 0); #endif - __set_tls(__tls_area); - ((unsigned *)__get_tls())[TLS_SLOT_THREAD_ID] = gettid(); + __libc_preinit(&__main_thread, __tls_area); debugger_init(); -- cgit v1.1