From 808694e8a330e32741b7781467610d8cec99ae6e Mon Sep 17 00:00:00 2001
From: Mike Frysinger <vapier@gentoo.org>
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