From 808694e8a330e32741b7781467610d8cec99ae6e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 8 Dec 2006 22:53:40 +0000 Subject: Richard Sandiford writes: add support for init/fini arrays in shared flat libraries --- libc/misc/internals/Makefile.in | 4 +- libc/misc/internals/__uClibc_main.c | 16 ++++++-- libc/misc/internals/shared_flat_add_library.c | 46 +++++++++++++++++++++++ libc/misc/internals/shared_flat_initfini.c | 53 +++++++++++++++++++++++++++ libc/misc/internals/shared_flat_lib.h | 35 ++++++++++++++++++ 5 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 libc/misc/internals/shared_flat_add_library.c create mode 100644 libc/misc/internals/shared_flat_initfini.c create mode 100644 libc/misc/internals/shared_flat_lib.h (limited to 'libc/misc') diff --git a/libc/misc/internals/Makefile.in b/libc/misc/internals/Makefile.in index a9638125d..af97b39af 100644 --- a/libc/misc/internals/Makefile.in +++ b/libc/misc/internals/Makefile.in @@ -18,7 +18,9 @@ MISC_INTERNALS_OBJ := $(patsubst %.c,$(MISC_INTERNALS_OUT)/%.o,$(CSRC)) libc-y += $(MISC_INTERNALS_OBJ) libc-shared-y += $(MISC_INTERNALS_OUT)/__uClibc_main.oS libc-static-y += $(MISC_INTERNALS_OUT)/__uClibc_main.o - +libc-static-$(HAVE_SHARED_FLAT) += \ + $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \ + $(MISC_INTERNALS_OUT)/shared_flat_add_library.o libc-nomulti-y += $(MISC_INTERNALS_OUT)/__uClibc_main.o objclean-y += misc_internals_objclean diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 7578a97fb..a2fbf6c89 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -88,7 +88,9 @@ extern void weak_function _locale_init(void) attribute_hidden; extern void weak_function __pthread_initialize_minimal(void); #endif -#ifdef __UCLIBC_CTOR_DTOR__ +/* If __HAVE_SHARED_FLAT__, all array initialisation and finalisation + * is handled by the routines passed to __uClibc_main(). */ +#if defined (__UCLIBC_CTOR_DTOR__) && !defined (__HAVE_SHARED_FLAT__) extern void _dl_app_init_array(void); extern void _dl_app_fini_array(void); # ifndef SHARED @@ -247,9 +249,11 @@ libc_hidden_proto(__uClibc_fini) void __uClibc_fini(void) { #ifdef __UCLIBC_CTOR_DTOR__ + /* If __HAVE_SHARED_FLAT__, all array finalisation is handled + * by __app_fini. */ # ifdef SHARED _dl_app_fini_array(); -# else +# elif !defined (__HAVE_SHARED_FLAT__) size_t i = __fini_array_end - __fini_array_start; while (i-- > 0) (*__fini_array_start [i]) (); @@ -348,7 +352,9 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc, /* Arrange for the application's dtors to run before we exit. */ __app_fini = app_fini; -# ifndef SHARED + /* If __HAVE_SHARED_FLAT__, all array initialisation is handled + * by __app_init. */ +# if !defined (SHARED) && !defined (__HAVE_SHARED_FLAT__) /* For dynamically linked executables the preinit array is executed by the dynamic linker (before initializing any shared object). For static executables, preinit happens rights before init. */ @@ -363,9 +369,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc, if (app_init!=NULL) { app_init(); } + /* If __HAVE_SHARED_FLAT__, all array initialisation is handled + * by __app_init. */ # ifdef SHARED _dl_app_init_array(); -# else +# elif !defined (__HAVE_SHARED_FLAT__) { const size_t size = __init_array_end - __init_array_start; size_t i; diff --git a/libc/misc/internals/shared_flat_add_library.c b/libc/misc/internals/shared_flat_add_library.c new file mode 100644 index 000000000..f03480f56 --- /dev/null +++ b/libc/misc/internals/shared_flat_add_library.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2006 CodeSourcery Inc + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * + * This file defines __shared_flat_add_library. If a library has + * initialistion and finalisation code, it should use this routine + * to register itself. + */ +#include "shared_flat_lib.h" + +/* The initialisation and finalisation symbols for this library. */ +extern void _init(void) attribute_hidden weak_function; +extern void _fini(void) attribute_hidden weak_function; +extern void (*__preinit_array_start[])(void) attribute_hidden; +extern void (*__preinit_array_end[])(void) attribute_hidden; +extern void (*__init_array_start[])(void) attribute_hidden; +extern void (*__init_array_end[])(void) attribute_hidden; +extern void (*__fini_array_start[])(void) attribute_hidden; +extern void (*__fini_array_end[])(void) attribute_hidden; + +/* The shared_flat_lib structure that describes this library. */ +static struct shared_flat_lib this_lib = { + 0, + 0, + __preinit_array_start, + __preinit_array_end, + __init_array_start, + __init_array_end, + __fini_array_start, + __fini_array_end, + _init, + _fini +}; + +/* Add this_lib to the end of the global list. */ +void __shared_flat_add_library(void) attribute_hidden; +void __shared_flat_add_library(void) +{ + this_lib.prev = __last_shared_lib; + if (this_lib.prev) + this_lib.prev->next = &this_lib; + else + __first_shared_lib = &this_lib; + __last_shared_lib = &this_lib; +} diff --git a/libc/misc/internals/shared_flat_initfini.c b/libc/misc/internals/shared_flat_initfini.c new file mode 100644 index 000000000..81e53834e --- /dev/null +++ b/libc/misc/internals/shared_flat_initfini.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2006 CodeSourcery Inc + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * + * This file defines the main initialisation and finalisation code for + * shared flat libraries. It in turn calls the initialisation and + * finalisation code for each registered library. + */ +#include "shared_flat_lib.h" + +/* A doubly-linked list of shared libraries. Those nearer the head + * of the list should be initialised first and finalised last. */ +struct shared_flat_lib *__first_shared_lib; +struct shared_flat_lib *__last_shared_lib; + +void __shared_flat_init(void) +{ + struct shared_flat_lib *lib; + void (**start)(void); + void (**end)(void); + + for (lib = __first_shared_lib; lib; lib = lib->next) { + end = lib->preinit_array_end; + for (start = lib->preinit_array_start; start < end; start++) + (*start)(); + } + + for (lib = __first_shared_lib; lib; lib = lib->next) { + if (lib->init) + lib->init(); + + end = lib->init_array_end; + for (start = lib->init_array_start; start < end; start++) + (*start)(); + } +} + +void __shared_flat_fini(void) +{ + struct shared_flat_lib *lib; + void (**start)(void); + void (**end)(void); + + for (lib = __last_shared_lib; lib; lib = lib->prev) { + start = lib->fini_array_start; + for (end = lib->fini_array_end; end > start;) + (*--end)(); + + if (lib->fini) + lib->fini(); + } +} diff --git a/libc/misc/internals/shared_flat_lib.h b/libc/misc/internals/shared_flat_lib.h new file mode 100644 index 000000000..e01213564 --- /dev/null +++ b/libc/misc/internals/shared_flat_lib.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2006 CodeSourcery Inc + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * + * This file defines the shared_flat_lib structure and the global library + * list. The structure is used to provide something close to ELF-like + * initialisation and finalisation when using shared flat libraries. + */ +#ifndef __SHARED_FLAT_LIB__ +#define __SHARED_FLAT_LIB__ + +struct shared_flat_lib { + struct shared_flat_lib *prev; + struct shared_flat_lib *next; + /* .preinit_array is usually only supported for executables. + * However, the distinction between the executable and its + * shared libraries isn't as pronounced for flat files; a shared + * library is really just a part of an executable that can be + * shared with other executables. We therefore allow + * .preinit_array to be used in libraries too. */ + void (**preinit_array_start)(void); + void (**preinit_array_end)(void); + void (**init_array_start)(void); + void (**init_array_end)(void); + void (**fini_array_start)(void); + void (**fini_array_end)(void); + void (*init)(void); + void (*fini)(void); +}; + +extern struct shared_flat_lib *__first_shared_lib; +extern struct shared_flat_lib *__last_shared_lib; + +#endif -- cgit v1.2.3