Revert "Fix the C library initialization to avoid calling static C++ constructors twice."

This reverts commit 03eabfe65e.
This commit is contained in:
David 'Digit' Turner 2009-06-03 19:32:37 +02:00
parent 03eabfe65e
commit 3a654b1e04
11 changed files with 94 additions and 273 deletions

View File

@ -30,35 +30,25 @@
.type _start,#function
.globl _start
# This is the small startup code that is called from
# the dynamic linker to execute an executable once all
# dependent shared libraries have been loaded and
# initialized.
# this is the small startup code that is first run when
# any executable that is statically-linked with Bionic
# runs.
#
# It's purpose is to call __libc_init as defined in
# bionic/libc_init_dynamic.c with appropriate
# it's purpose is to call __libc_init with appropriate
# arguments, which are:
#
# - the address of the raw data block setup by the Linux
# kernel ELF loader
#
# - address of an "onexit" function (not used on any
# platform supported by Bionic)
# - address of an "onexit" function, not used on any
# platform supported by Bionic
#
# - address of the "main" function of the program. We
# can't hard-code it in the adr pseudo instruction
# so we use a tiny trampoline that will get relocated
# by the dynamic linker before this code runs
#
# - address of the constructors table, i.e. a table
# that points to various initialization and
# finalization sections for the program.
#
# NOTE: This code is currently placed in shared libraries
# by the build system, but will be ignored.
#
# On the other hand, the arrays defined below are
# required and will be parsed by the dynamic linker.
# - address of the constructor list
#
_start:
mov r0, sp

View File

@ -30,27 +30,25 @@
.type _start,#function
.globl _start
# This is the small startup code that is first run when
# any static executable runs. A static executable is one
# that is started directly by the Linux kernel, not from
# the dynamic linker, it thus cannot depend on any shared
# library.
# this is the small startup code that is first run when
# any executable that is statically-linked with Bionic
# runs.
#
# It's purpose is to call __libc_init as defined in
# bionic/libc_init_static.c with appropriate
# it's purpose is to call __libc_init with appropriate
# arguments, which are:
#
# - the address of the raw data block setup by the Linux
# kernel ELF loader
#
# - address of an "onexit" function (not used on any
# platform supported by Bionic).
# - address of an "onexit" function, not used on any
# platform supported by Bionic
#
# - address of the "main" function of the program.
# - address of the "main" function of the program. We
# can't hard-code it in the adr pseudo instruction
# so we use a tiny trampoline that will get relocated
# by the dynamic linker before this code runs
#
# - address of the constructors table, i.e. a table
# that points to various initialization and
# finalization sections for the program.
# - address of the constructor list
#
_start:
mov r0, sp
@ -61,13 +59,6 @@ _start:
0: b main
# The "C++ ABI for ARM" document that static C++ constructors
# shall only be called from the .init_array section.
#
# Do we really need a .ctors section on ARM platforms ?
# It looks like it will always be empty.
#
1: .long __PREINIT_ARRAY__
.long __INIT_ARRAY__
.long __FINI_ARRAY__

View File

@ -29,35 +29,25 @@
.type _start, @function
.globl _start
# This is the small startup code that is called from
# the dynamic linker to execute an executable once all
# dependent shared libraries have been loaded and
# initialized.
# this is the small startup code that is first run when
# any executable that is statically-linked with Bionic
# runs.
#
# It's purpose is to call __libc_init as defined in
# bionic/libc_init_dynamic.c with appropriate
# it's purpose is to call __libc_init with appropriate
# arguments, which are:
#
# - the address of the raw data block setup by the Linux
# kernel ELF loader
#
# - address of an "onexit" function (not used on any
# platform supported by Bionic)
# - address of an "onexit" function, not used on any
# platform supported by Bionic
#
# - address of the "main" function of the program. We
# can't hard-code it in the adr pseudo instruction
# so we use a tiny trampoline that will get relocated
# by the dynamic linker before this code runs
#
# - address of the constructors table, i.e. a table
# that points to various initialization and
# finalization sections for the program.
#
# NOTE: This code is currently placed in shared libraries
# by the build system, but will be ignored.
#
# On the other hand, the arrays defined below are
# required and will be parsed by the dynamic linker.
# - address of the constructor list
#
_start:
mov %esp, %eax

View File

@ -29,27 +29,25 @@
.type _start, @function
.globl _start
# This is the small startup code that is first run when
# any static executable runs. A static executable is one
# that is started directly by the Linux kernel, not from
# the dynamic linker, it thus cannot depend on any shared
# library.
# this is the small startup code that is first run when
# any executable that is statically-linked with Bionic
# runs.
#
# It's purpose is to call __libc_init as defined in
# bionic/libc_init_static.c with appropriate
# it's purpose is to call __libc_init with appropriate
# arguments, which are:
#
# - the address of the raw data block setup by the Linux
# kernel ELF loader
#
# - address of an "onexit" function (not used on any
# platform supported by Bionic).
# - address of an "onexit" function, not used on any
# platform supported by Bionic
#
# - address of the "main" function of the program.
# - address of the "main" function of the program. We
# can't hard-code it in the adr pseudo instruction
# so we use a tiny trampoline that will get relocated
# by the dynamic linker before this code runs
#
# - address of the constructors table, i.e. a table
# that points to various initialization and
# finalization sections for the program.
# - address of the constructor list
#
_start:
mov %esp, %eax

View File

@ -39,11 +39,8 @@
#include <bionic_tls.h>
#include <errno.h>
/* This contains the common C library initialization code.
* To understand what happens here, you should read the
* "Initialization and Finalization" section of the file
* named bionic/linker/README.TXT
*/
extern void _init(void);
extern void _fini(void);
static void call_array(void(**list)())
{
@ -53,6 +50,15 @@ static void call_array(void(**list)())
}
}
static void __bionic_do_global_dtors(structors_array_t const * const p)
{
call_array(p->fini_array);
//_fini();
}
extern unsigned __get_sp(void);
extern pid_t gettid(void);
char* __progname;
char **environ;
@ -63,28 +69,30 @@ unsigned int __page_shift = PAGE_SHIFT;
int __system_properties_init(void);
/* This function can be run under two different contexts:
*
* - for statically linked executables (i.e. those who do
* not depend on shared libraries at all), it will be
* called from the __libc_init() function defined in
* bionic/libc_init_static.c
*
* - for dynamic executables, it will be called from the
* __libc_init() function defined in bionic/libc_init_dynamic.c
*
*/
void __libc_init_common(uintptr_t *elfdata,
void (*onexit)(void),
int (*slingshot)(int, char**, char**),
structors_array_t const * const structors,
void (*pre_ctor_hook)())
{
pthread_internal_t thread;
pthread_attr_t thread_attr;
void *tls_area[BIONIC_TLS_SLOTS];
int argc;
char **argv, **envp, **envend;
struct auxentry *auxentry;
unsigned int page_size = 0, page_shift = 0;
/* The main thread's stack has empirically shown to be 84k */
unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
unsigned stacksize = 128 * 1024; //84 * 1024;
unsigned stackbottom = stacktop - stacksize;
pthread_attr_init(&thread_attr);
pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);
_init_thread(&thread, gettid(), &thread_attr, (void*)stackbottom);
__init_tls(tls_area, &thread);
argc = (int) *elfdata++;
argv = (char**) elfdata;
envp = argv+(argc+1);
@ -98,17 +106,17 @@ void __libc_init_common(uintptr_t *elfdata,
if (pre_ctor_hook) pre_ctor_hook();
if (structors != NULL) {
// XXX: we should execute the .fini_array upon exit
// pre-init array.
// XXX: I'm not sure what's the different with the init array.
call_array(structors->preinit_array);
// for compatibility with non-eabi binary, call the .ctors section
// this is only useful for static non-ARM (e.g. x86) executables.
call_array(structors->ctors_array);
// call static constructors
call_array(structors->init_array);
}
exit(slingshot(argc, argv, envp));
}

View File

@ -25,29 +25,18 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* libc_init_static.c
*
* This function is called for dynamic executables after the dynamic
* linker has loaded and initialized all dependent shared libraries.
*
* It takes the raw data block set up by the ELF loader
* in the kernel and parses it.
* This function takes the raw data block set up by the ELF loader
* in the kernel and parses it. It is invoked by crt0.S which makes
* any necessary adjustments and passes calls this function using
* the standard C calling convention.
*
* The arguments are:
* elfdata -- The ELF loader data block; usually from the stack.
* uintptr_t *elfdata -- The ELF loader data block; usually from the stack.
* Basically a pointer to argc.
*
* onexit -- Function to call on exit, can be NULL.
*
* slingshot -- Address of the program's main function
*
* structors -- Table of constructor functions arrays that must
* be called before the slingshot.
*
* It is called from the assembly fragment found in
* arch-$ARCH/bionic/crtbegin_dynamic.S
* void (*onexit)(void) -- Function to install into onexit
*/
/*
@ -73,18 +62,5 @@ __noreturn void __libc_init(uintptr_t *elfdata,
int (*slingshot)(int, char**, char**),
structors_array_t const * const structors)
{
/* NOTE: At this point, the dynamic linker has *already* called
* all initializers properly, so we ignore 'structors' to
* avoid calling them twice.
*/
/* NOTE2: Is it worthwhile to use malloc_debug_init() in the case of
* of the non-debug shared C library ?
*
* The implementation in bionic/malloc_leak.c contains a lot
* of code which will turn to be unused, and we add a dispatch
* overhead to malloc() et al. that proved to be significant
* in the past (e.g. making boot sequence 5% slower)
*/
__libc_init_common(elfdata, onexit, slingshot, NULL, malloc_debug_init);
__libc_init_common(elfdata, onexit, slingshot, structors, malloc_debug_init);
}

View File

@ -25,30 +25,18 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* libc_init_static.c
*
* This function is called for static executables, i.e. those that
* dont depend on shared libraries and are directly started by the
* Linux kernel.
*
* It takes the raw data block set up by the ELF loader
* in the kernel and parses it.
* This function takes the raw data block set up by the ELF loader
* in the kernel and parses it. It is invoked by crt0.S which makes
* any necessary adjustments and passes calls this function using
* the standard C calling convention.
*
* The arguments are:
* elfdata -- The ELF loader data block; usually from the stack.
* uintptr_t *elfdata -- The ELF loader data block; usually from the stack.
* Basically a pointer to argc.
*
* onexit -- Function to call on exit, can be NULL.
*
* slingshot -- Address of the program's main function
*
* structors -- Table of constructor functions arrays that must
* be called before the slingshot.
*
* It is called from the assembly fragment found in
* arch-$ARCH/bionic/crtbegin_static.S
* void (*onexit)(void) -- Function to install into onexit
*/
/*
@ -63,19 +51,18 @@
#include <stdlib.h>
#include <stdint.h>
#include <elf.h>
#include "bionic_preinit.h"
#include "pthread_internal.h"
#include "atexit.h"
#include "libc_init_common.h"
#include <bionic_tls.h>
#include <errno.h>
__noreturn void __libc_init(uintptr_t *elfdata,
void (*onexit)(void),
int (*slingshot)(int, char**, char**),
structors_array_t const * const structors)
{
pthread_internal_t thread;
void *tls_area[BIONIC_TLS_SLOTS];
__libc_preinit( &thread, tls_area );
/*
* To enable malloc checks for statically linked programs, add
* "WITH_MALLOC_CHECK_LIBC_A := true" in device/buildspec.mk

View File

@ -1,76 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _BIONIC_PREINIT_H
#define _BIONIC_PREINIT_H
#include "pthread_internal.h"
#include "bionic_tls.h"
#include <asm/page.h>
/* this function is used to perform a minimal initialization of the
* the C library. This must be performed before any other call to
* other functions, in either the dynamic linker's startup code
* or libc_init_static.c
*
* 'main_thread' and 'tls_area' must be persistent variables,
* which means they must be either global, or allocated in the
* main thread's stack frame and never, ever, freed before
* program exit.
*
* VERY IMPORTANT NOTE:
*
* THIS IMPLEMENTATION SHOULD NOT USE GLOBAL VARIABLES.
*
* The reason is the dynamic linker's tricky usage of C library
* functions and later renaming of their symbols. See the
* "C Library Usage Restriction" section in bionic/linker/README.TXT
* for details.
*/
extern unsigned __get_sp(void);
extern pid_t gettid(void);
static __inline__ void
__libc_preinit( pthread_internal_t* main_thread,
void* tls_area[BIONIC_TLS_SLOTS] )
{
pthread_attr_t thread_attr;
/* Setup the main thread's information */
unsigned stacktop = (__get_sp() & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
unsigned stacksize = 128 * 1024;
unsigned stackbottom = stacktop - stacksize;
pthread_attr_init(&thread_attr);
pthread_attr_setstack(&thread_attr, (void*)stackbottom, stacksize);
_init_thread(main_thread, gettid(), &thread_attr, (void*)stackbottom);
__init_tls(tls_area, main_thread);
}
#endif /* _BIONIC_INIT_H */

View File

@ -112,46 +112,3 @@ 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.

View File

@ -44,7 +44,7 @@
#include <sys/atomics.h>
/* special private C library header - see Android.mk */
#include <bionic_preinit.h>
#include <bionic_tls.h>
#include "linker.h"
#include "linker_debug.h"
@ -1691,7 +1691,6 @@ 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)
{
@ -1710,7 +1709,8 @@ unsigned __linker_init(unsigned **elfdata)
gettimeofday(&t0, 0);
#endif
__libc_preinit(&__main_thread, __tls_area);
__set_tls(__tls_area);
((unsigned *)__get_tls())[TLS_SLOT_THREAD_ID] = gettid();
debugger_init();