[PATCH/RFC] PIC and flat shared library support for m68k

Richard Sandiford richard at codesourcery.com
Thu Jul 6 05:10:30 PDT 2006


This patch adds m68k support for flat shared libraries and uClinux-style
PIC.  The reason I've stuck "RFC" in the subject line is that the shared
library side of things is rather different from the uClinux-dist version,
and this might make the patch a little controversial.  However, the new
approach should still be compatible with the old one, as explained below.

Stepping back a bit, the traditional method for building flat shared
libraries does not allow either the libraries or the executable to have
constructors and destructors:

  http://www.ucdot.org/article.pl?sid=03/11/25/1126257&mode=thread

I wanted to remove this restriction.  I also wanted to remove the
need for the user to provide an implementation of main() for shared
libraries; constructors make this unnecessary.

The patch does this by adding a separate shared-library version of
crt1.o called Scrt1.o (as for ELF shared libraries).  The entry point
is called lib_main() to retain compatibility with the traditional build
system.

When the new shared flat library support is enabled, both executables
and shared libraries will use a "library"[1] registration function
called __shared_flat_add_library().  This function will arrange for
the library's _init, _fini, .preinit_array, etc., to be used.
__uClibc_main() will then be passed pointers to __shared_flat_init() and
__shared_flat_fini(), which do the actual constructing and destructing.

The traditional build system will still work because it suppresses
the normal start and end files.  Neither crt1.o nor Scrt1.o will be used,
and the new __shared_flat_*() routines will not be pulled in from libc.a.

To take full advantage of the new scheme, gcc needs to select Scrt1.o
rather than crt1.o in STARTFILE_SPEC when linking shared libraries (i.e.
when -shared-lib-id is nonzero).  gcc's csl/coldfire-4_1 branch contains
this change, and we hope to merge it into gcc mainline during stage 1 of
4.3.  You can then link libraries with:

    m68k-uclinux-gcc -mid-shared-library -mshared-library-id=N \
      -o foo ...inputs...

which is much simpler than the traditional link line.  In the meantime,
you can use -nostartfiles and list Scrt1.o, crti.o, crtbegin.o, crtend.o
and crtn.o manually.

Other notes:

  - We now have three ways of loading an external text symbol: absolute,
    PC-relative and GOT-based.  We need GOT-based accesses for
    -mid-shared-library because the symbol might be provided by a
    dependent library.  However, PC-relative accesses are otherwise
    better than GOT accesses because they don't involve any run-time
    relocations.

    Rather than scatter conditional logic throughout sysdeps/linux/m68k,
    I've added a new file -- m68k_pic.S -- that encapsulates the differences.

  - The patch adds new configuration options for building a shared libc.
    Unfortunately, this libc will not be usable as-is, because libc.gdb
    will export all global symbols, including those which are supposed
    to be local to the library.

    The traditional way of dealing with this has been to run a separate
    objcopy post-pass that uses -L to localise specific symbols by name
    (see the page linked above for details).  However, I think a better
    approach is to localise every hidden symbol, and objcopy now has a
    --localize-hidden option to do just that:

      http://sources.redhat.com/ml/binutils/2006-06/msg00204.html

    This option isn't yet in any released binutils though (it'll be in 2.18).

    I'll soon submit a patch to uclinux-dev that (subject to
    configuration options) will make ld-elf2flt use --localize-hidden
    on shared libraries by default.  I hope this might eventually become
    standard, so no post-processing step is necessary, either in the libc
    makefile, or in user makefiles.

    In other words, I've written the makefile so that it will work
    out-of-box with the patched ld-elf2flt, when configured appropriately,
    but so that the user will need a separate post-processing step otherwise.
    I don't know if that's acceptable.

  - The only existing mention of flat library support in uClibc mainline
    appears to be the block at the end of Rules.mak.  However, that
    block is conditional on CONFIG_BINFMT_SHARED_FLAT, which isn't a
    uClibc option, and sets variables that are not used within the
    uClibc tree itself.  I've therefore removed the block in this patch.
    I assume it was there to help the uClinux build process, but if we go
    with something like the patch below, it shouldn't be needed any more.

Hopefully the comments in the patch are enough to explain the rest.
Let me know if not though (it's not easy to tell when you're so
close to the thiing).

Tested on an M5208EVB with default options, -msep-data, and
-mid-shared-library (using a shared libc).  Does it look OK?

Richard

[1] On uClinux, an executable is treated as shared library 0.

FWIW, here's a GNU-style changelog, in case it's useful:

	* extra/Configs/Config.in (HAVE_SHARED_FLAT): New option.
	(SHARED_FLAT_ID): Likewise.
	* Makefile.in (install_dev): If HAVE_SHARED_FLAT, install the
	shared flat libraries and their aassociated .gdb files.
	* Makerules (libs): Depend on $(lib-gdb-y) if HAVE_SHARED_FLAT.
	(LINK_FLAT_CRTS): New variable.
	(link-flat.so): New multiline variable.
	(CRTS): Add S$(CRT).o for HAVE_SHARED_FLAT too.
	* Rules.mak: Remove old CONFIG_BINFMT_SHARED_FLAT handling.
	* libc/Makefile.in (lib-gdb-y): Add $(top_builddir)lib/libc.gdb.
	($(top_builddir)lib/libc.gdb): New rule.
	* libc/sysdeps/linux/m68k/m68k_pic.S: New file.
	* libc/sysdeps/linux/m68k/clone.S: Include m68k_pic.S.
	(clone): Branch to syscall_error_trampoline rather than syscall_error.
	(__syscall_error_trampoline): New.  Use JUMP to jump to
	__syscall_error.
	* libc/sysdeps/linux/m68k/crti.S: Include m68k_pic.S.
	Remove gcc-derived .file and .ident directives.
	(init): Remove APP and NO_APP markers.  Use INIT_GP.
	(fini): Likewise.
	* libc/sysdeps/linux/m68k/setjmp.S: Include m68k_pic.S.
	(__sigsetjmp): JUMP to __sigjmp_save.
	* libc/sysdeps/linux/m68k/crtn.S: Include m68k_pic.S.
	Remove gcc-derived .file and .ident directives.  Use FINI_GP.
	* libc/sysdeps/linux/m68k/bsd-setjmp.S: Include m68k_pic.S.
	(setjmp): JUMP to __sigjmp_save.
	* libc/sysdeps/linux/m68k/crt1.S: Include features.h and m68k_pic.S.
	(_start): Guard with #ifndef L_Scrt1.  Initialize the GOT for uClinux
	PIC.  Call __shared_flat_add_library if using shared flat libraries.
	If using shared flat libraries, pass __shared_flat_fini and
	__shared_flat_init rather than _fini and _init.  Use PEA_TEXT to
	push text addresses and CALL to call functions.
	(lib_main): New routine, selected when L_Scrt1 is defined.
	* libc/misc/internals/Makefile.in (libc-static-$(HAVE_SHARED_FLAT)):
	Add shared_flat_initfini.o and shared_flat_add_library.o.
	* libc/misc/internals/__uClibc_main.c: Guard init/fini array
	definitions with !defined (__HAVE_SHARED_FLAT__).
	(__uClibc_fini): Do not perform separate array finalisation
	if __HAVE_SHARED_FLAT__.
	(__uClibc_main): Likewise initialisation.
	* libc/misc/internals/shared_flat_initfini.c: New file.
	* libc/misc/internals/shared_flat_lib.h: Likewise.
	* libc/misc/internals/shared_flat_add_library.c: Likewise.

Signed-off-by: Richard Sandiford <richard at codesourcery.com>

-------------- next part --------------
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 15618)
+++ Makefile.in	(working copy)
@@ -246,6 +246,15 @@ ifeq ($(DOPIC),y)
 	fi
 endif
 endif
+ifeq ($(HAVE_SHARED_FLAT),y)
+	for file in lib/lib*.gdb; do \
+		if test -f $$file; then \
+			$(INSTALL) -m 755 $$file $(PREFIX)$(DEVEL_PREFIX)lib; \
+			$(INSTALL) -m 755 `echo $$file | sed 's/\.gdb$$//'` \
+			  $(PREFIX)$(DEVEL_PREFIX)lib; \
+		fi; \
+	done
+endif
 
 # Installs run-time libraries
 install_runtime:
Index: extra/Configs/Config.in
===================================================================
--- extra/Configs/Config.in	(revision 15618)
+++ extra/Configs/Config.in	(working copy)
@@ -196,6 +196,30 @@ config DOPIC
 	  If you wish to build all of uClibc as PIC objects, then answer Y here.
 	  If you are unsure, then you should answer N.
 
+config HAVE_SHARED_FLAT
+	bool "Generate a flat-format shared library"
+	default n
+	depends on !ARCH_USE_MMU
+	help
+	  Answer Y here if you are using uClinux and wish to build uClibc
+	  as a flat-format shared library.
+
+config SHARED_FLAT_ID
+	int "Shared library id"
+	default 1
+	depends on HAVE_SHARED_FLAT
+	help
+	  When using flat shared libraries, every library has a unique
+	  system-wide identifier.  Identifier 0 is reserved for
+	  executables and true shared libraries have identifiers
+	  starting at 1.  The maximum shared library identifier is
+	  determined by the kernel and is usually 3.  Shared library
+	  N must be available on the target system as "/lib/libN.so".
+
+	  When a shared C library is used, it usually has identifier 1,
+	  but you can use this option to select a different identifier
+	  if you need to.
+
 config HAVE_NO_SHARED
 	bool
 	default n
Index: Makerules
===================================================================
--- Makerules	(revision 15618)
+++ Makerules	(working copy)
@@ -11,6 +11,9 @@ libs: $(lib-so-y) $(lib-a-y)
 $(lib-so-y): $(interp)
 else
 .LIBPATTERNS: "lib%.a"
+ifeq ($(HAVE_SHARED_FLAT),y)
+libs: $(lib-gdb-y)
+endif
 libs: $(lib-a-y)
 endif
 objs: all_objs
@@ -131,6 +134,29 @@ define link.so
 	$(Q)$(LN) -sf $(1) $@
 endef
 
+# CRT files needed by link-flat.so
+LINK_FLAT_CRTS := $(top_builddir)lib/Scrt1.o $(top_builddir)lib/crti.o \
+	$(top_builddir)lib/crtn.o
+
+# Create a shared flat library from the archive named by the first dependency.
+# $@ names the shared library's .gdb file, not the flat file itself.
+# (This is because the .gdb suffix makes the ELF file more distinctive
+# than the suffixless flat file.)
+#
+# Argument 1 is the shared library file -- i.e. $(@:.gdb=) -- and argument 2
+# is the shared library identifier.  If it wasn't for $(disp_ld), we could
+# avoid passing $(@:.gdb=) as an argument and use $(@:.gdb=) instead of $(1).
+define link-flat.so
+	$(Q)$(INSTALL) -d $(dir $@)
+	$(Q)$(RM) $(1) $@
+	@$(disp_ld)
+	$(Q)$(LD) $(LDFLAGS-$(notdir $@)) -o $(1) \
+		-elf2flt -shared-lib-id $(2) $(top_builddir)lib/Scrt1.o \
+		$(top_builddir)/lib/crti.o --whole-archive $(firstword $^) \
+		--no-whole-archive $(LIBS-$(notdir $@)) $(LIBGCC) \
+		$(top_builddir)/lib/crtn.o
+endef
+
 define linkm.so
 	$(Q)$(INSTALL) -d $(dir $@)
 	$(Q)$(RM) $@ $@.$(2) $(dir $@)$(1)
@@ -183,7 +209,7 @@ $(headers_dep):
 
 CRT := crt1
 
-ifeq ($(HAVE_SHARED),y)
+ifeq ($(HAVE_SHARED)$(HAVE_SHARED_FLAT),y)
 CRTS=$(top_builddir)lib/$(CRT).o $(top_builddir)lib/S$(CRT).o
 else
 CRTS=$(top_builddir)lib/$(CRT).o
Index: Rules.mak
===================================================================
--- Rules.mak	(revision 15618)
+++ Rules.mak	(working copy)
@@ -489,16 +489,3 @@ ifeq ($(UCLIBC_CTOR_DTOR),y)
 SHARED_START_FILES:=$(top_builddir)lib/crti.o $(LIBGCC_DIR)crtbeginS.o
 SHARED_END_FILES:=$(LIBGCC_DIR)crtendS.o $(top_builddir)lib/crtn.o
 endif
-
-########################################
-#
-# uClinux shared lib support
-#
-
-ifeq ($(CONFIG_BINFMT_SHARED_FLAT),y)
-  # For the shared version of this, we specify no stack and its library ID
-  FLTFLAGS += -s 0
-  LIBID=1
-  export LIBID FLTFLAGS
-  SHARED_TARGET = lib/libc
-endif
Index: libc/Makefile.in
===================================================================
--- libc/Makefile.in	(revision 15618)
+++ libc/Makefile.in	(working copy)
@@ -51,6 +51,7 @@ libc-multi-y = $(filter-out $(libc-nomul
 endif
 
 lib-a-y += $(top_builddir)lib/libc.a
+lib-gdb-y += $(top_builddir)lib/libc.gdb
 lib-so-y += $(libc)
 objclean-y += libc_clean
 
@@ -90,5 +91,8 @@ $(top_builddir)lib/libc.a: $(libc-a-y) |
 	$(do_strip)
 	$(do_ar)
 
+$(top_builddir)lib/libc.gdb: $(top_builddir)lib/libc.a $(LINK_FLAT_CRTS)
+	$(call link-flat.so,$(@:.gdb=),$(SHARED_FLAT_ID))
+
 libc_clean:
 	$(RM) $(libc_OUT)/*.{o,os,oS,a}
Index: libc/sysdeps/linux/m68k/m68k_pic.S
===================================================================
--- libc/sysdeps/linux/m68k/m68k_pic.S	(revision 0)
+++ libc/sysdeps/linux/m68k/m68k_pic.S	(revision 0)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006 CodeSourcery Inc
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ * This file defines some m68k assembly macros for handling the differences
+ * between PIC and non-PIC.
+ */
+#include <features.h>
+
+	/* When assembling code for shared flat libraries, this is nonzero
+	   if %a5 points the current library's GOT.  */
+	.equ	have_current_got, 0
+
+	/* Perform the equivalent of "<op> <target>", where <target> is
+	   a text address.  <tmp> is available as a temporary address
+	   register.  */
+	.macro	DO_TEXT op,target,tmp
+#if defined __HAVE_SHARED_FLAT__
+	.ifne	have_current_got
+	move.l \target at GOT(%a5),\tmp
+	.else
+	move.l _current_shared_library_a5_offset_(%a5),\tmp
+	move.l \target at GOT(\tmp),\tmp
+	.endif
+	\op (\tmp)
+#elif defined __PIC__
+	lea \target-.-8,\tmp
+	\op (%pc,\tmp)
+#else
+	\op \target
+#endif
+	.endm
+
+	/* Do "pea <target>" when <target> is a text address.
+	   <tmp> is available as a temporary register.  */
+	.macro PEA_TEXT target,tmp
+	DO_TEXT pea,\target,\tmp
+	.endm
+
+	/* Likewise jsr.  */
+	.macro CALL target,tmp
+	DO_TEXT jsr,\target,\tmp
+	.endm
+
+	/* Likewise jmp.  */
+	.macro JUMP target,tmp
+	DO_TEXT jmp,\target,\tmp
+	.endm
+
+	/* Initialize the global pointer, if functions need to do that.  */
+	.macro INIT_GP
+#if defined __HAVE_SHARED_FLAT__
+	move.l	%a5,-(%sp)
+	move.l _current_shared_library_a5_offset_(%a5),%a5
+#endif
+	.endm
+
+	/* Undo the effects of INIT_GP.  */
+	.macro FINI_GP
+#if defined __HAVE_SHARED_FLAT__
+	move.l	(%sp)+,%a5
+#endif
+	.endm
Index: libc/sysdeps/linux/m68k/clone.S
===================================================================
--- libc/sysdeps/linux/m68k/clone.S	(revision 15618)
+++ libc/sysdeps/linux/m68k/clone.S	(working copy)
@@ -8,6 +8,7 @@
 #include <features.h>
 #include <bits/errno.h>
 #include <sys/syscall.h>
+#include "m68k_pic.S"
 
 /* int _clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
 
@@ -21,11 +22,11 @@ clone:
 	movel   4(%sp), %d1             /* no NULL function pointers */
 	movel	%d1, %a0
 	tstl    %d1
-	jbeq    __syscall_error
+	beq.w	__syscall_error_trampoline
 	movel   8(%sp), %d1             /* no NULL stack pointers */
 	movel	%d1, %a1
 	tstl    %d1
-	jbeq    __syscall_error
+	beq.w   __syscall_error_trampoline
 
 	/* Allocate space and copy the argument onto the new stack.  */
 	movel   16(%sp), -(%a1)
@@ -50,7 +51,7 @@ clone:
 #endif
 
 	tstl    %d0
-	jbmi    __syscall_error
+	bmi.w   __syscall_error_trampoline
 	beq.w   thread_start
 
 	rts
@@ -62,3 +63,7 @@ thread_start:
 	movel	#__NR_exit, %d0
 	trap	#0
 	/*jsr    exit*/
+
+__syscall_error_trampoline:
+	JUMP	__syscall_error,%a0
+
Index: libc/sysdeps/linux/m68k/crti.S
===================================================================
--- libc/sysdeps/linux/m68k/crti.S	(revision 15618)
+++ libc/sysdeps/linux/m68k/crti.S	(working copy)
@@ -1,27 +1,17 @@
-	.file	"initfini.c"
-#APP
-	
+#include "m68k_pic.S"
+
 	.section .init
-#NO_APP
 	.align	2
 	.globl	_init
 	.type	_init, @function
 _init:
-	link.w %a6,#0
-#APP
-	
-	.align 2
-	
+	link.w	%a6,#0
+	INIT_GP
 	
 	.section .fini
-#NO_APP
 	.align	2
 	.globl	_fini
 	.type	_fini, @function
 _fini:
-	link.w %a6,#0
-#APP
-	.align 2
-	
-	
-	.ident	"GCC: (GNU) 3.3.2"
+	link.w	%a6,#0
+	INIT_GP
Index: libc/sysdeps/linux/m68k/setjmp.S
===================================================================
--- libc/sysdeps/linux/m68k/setjmp.S	(revision 15618)
+++ libc/sysdeps/linux/m68k/setjmp.S	(working copy)
@@ -5,6 +5,7 @@
 #define _ASM
 #define _SETJMP_H
 #include <bits/setjmp.h>
+#include "m68k_pic.S"
 
 .globl __sigsetjmp;
 .type  __sigsetjmp, at function
@@ -18,6 +19,5 @@ __sigsetjmp:
 	fmovemx %fp2-%fp7, %a0@(JB_FPREGS)
 #endif
 	clrl	%d0
-	lea		__sigjmp_save-.-8, %a0
-	jmp		0(%pc, %a0)
+	JUMP	__sigjmp_save,%a0
 
Index: libc/sysdeps/linux/m68k/crtn.S
===================================================================
--- libc/sysdeps/linux/m68k/crtn.S	(revision 15618)
+++ libc/sysdeps/linux/m68k/crtn.S	(working copy)
@@ -1,26 +1,11 @@
-	.file	"initfini.c"
-#APP
-	
+#include "m68k_pic.S"
+
 	.section .init
-#NO_APP
-	.align	2
-	.globl	_init
-	.type	_init, @function
-#NO_APP
-	unlk %a6
+	FINI_GP
+	unlk	%a6
 	rts
-	.size	_init, .-_init
-#APP
 	
 	.section .fini
-#NO_APP
-	.align	2
-	.globl	_fini
-	.type	_fini, @function
-#NO_APP
-	unlk %a6
+	FINI_GP
+	unlk	%a6
 	rts
-	.size	_fini, .-_fini
-#APP
-	
-	.ident	"GCC: (GNU) 3.3.2"
Index: libc/sysdeps/linux/m68k/bsd-setjmp.S
===================================================================
--- libc/sysdeps/linux/m68k/bsd-setjmp.S	(revision 15618)
+++ libc/sysdeps/linux/m68k/bsd-setjmp.S	(working copy)
@@ -5,6 +5,7 @@
 #define _ASM
 #define _SETJMP_H
 #include <bits/setjmp.h>
+#include "m68k_pic.S"
 
 .globl setjmp;
 .type  setjmp, at function
@@ -18,6 +19,5 @@ setjmp:
 	fmovemx %fp2-%fp7, %a0@(JB_FPREGS)
 #endif
 	clrl	%d0
-	lea		__sigjmp_save-.-8, %a0
-	jmp		0(%pc, %a0)
+	JUMP	__sigjmp_save,%a0
 
Index: libc/sysdeps/linux/m68k/crt1.S
===================================================================
--- libc/sysdeps/linux/m68k/crt1.S	(revision 15618)
+++ libc/sysdeps/linux/m68k/crt1.S	(working copy)
@@ -34,6 +34,10 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <features.h>
+#include "m68k_pic.S"
+
+#ifndef L_Scrt1
 /* This is the canonical entry point, usually the first thing in the text
    segment.  The SVR4/m68k ABI says that when the entry point runs,
    most registers' values are unspecified, except for:
@@ -60,8 +64,6 @@
 		8(%sp)			envp
 */
 
-#include <features.h>
-
 	.text
 	.type	_init,%function
 	.type	_fini,%function
@@ -76,6 +78,17 @@ _start:
 	   the outermost frame obviously.  */
 	sub.l %fp, %fp
 
+#if !defined __ARCH_USE_MMU__ && defined __PIC__
+	/* Set up the global pointer.  The GOT is at the beginning of the
+	   data segment, whose address is in %d5.  */
+	move.l %d5,%a5
+	.equ have_current_got, 1
+#endif
+	
+#ifdef __HAVE_SHARED_FLAT__
+	CALL __shared_flat_add_library,%a1
+#endif
+
 	/* Extract the arguments as encoded on the stack and set up the
 	   arguments for `main': argc, argv.  envp will be determined
 	   later in __libc_start_main.  */
@@ -100,19 +113,35 @@ _start:
 
 	/* Push the address of our own entry points to `.fini' and
 	   `.init'.  */
-	pea _fini
-	pea _init
+#if defined __HAVE_SHARED_FLAT__
+	PEA_TEXT __shared_flat_fini,%a1
+	PEA_TEXT __shared_flat_init,%a1
+#else
+	PEA_TEXT _fini,%a1
+	PEA_TEXT _init,%a1
+#endif
 
 	pea (%a0)		/* Push second argument: argv.  */
 	move.l %d0, -(%sp)	/* Push first argument: argc.  */
 
-	pea main
+	PEA_TEXT main,%a1
 
 	/* Call the user's main function, and exit with its value.  But
 	   let the libc call main.  */
-	jbsr __uClibc_main
+	CALL __uClibc_main,%a1
 
 	illegal			/* Crash if somehow `exit' does return.  */
+#else
+	.text
+	.globl lib_main
+	.hidden lib_main
+	.type lib_main, at function
+lib_main:
+	move.l %d5,%a5
+	JUMP __shared_flat_add_library,%a0
+
+	.hidden _current_shared_library_a5_offset_
+#endif
 
 /* Define a symbol for the first piece of initialized data.  */
 	.data
Index: libc/misc/internals/Makefile.in
===================================================================
--- libc/misc/internals/Makefile.in	(revision 15618)
+++ libc/misc/internals/Makefile.in	(working copy)
@@ -19,7 +19,9 @@ MISC_INTERNALS_OBJ := $(patsubst %.c,$(M
 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
Index: libc/misc/internals/__uClibc_main.c
===================================================================
--- libc/misc/internals/__uClibc_main.c	(revision 15618)
+++ libc/misc/internals/__uClibc_main.c	(working copy)
@@ -88,7 +88,9 @@ extern void weak_function _locale_init(v
 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]) ();
@@ -347,7 +351,9 @@ void __uClibc_main(int (*main)(int, char
     /* 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.  */
@@ -362,9 +368,11 @@ void __uClibc_main(int (*main)(int, char
     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;
Index: libc/misc/internals/shared_flat_initfini.c
===================================================================
--- libc/misc/internals/shared_flat_initfini.c	(revision 0)
+++ libc/misc/internals/shared_flat_initfini.c	(revision 0)
@@ -0,0 +1,55 @@
+/*
+ * 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();
+    }
+}
Index: libc/misc/internals/shared_flat_lib.h
===================================================================
--- libc/misc/internals/shared_flat_lib.h	(revision 0)
+++ libc/misc/internals/shared_flat_lib.h	(revision 0)
@@ -0,0 +1,34 @@
+/*
+ * 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
Index: libc/misc/internals/shared_flat_add_library.c
===================================================================
--- libc/misc/internals/shared_flat_add_library.c	(revision 0)
+++ libc/misc/internals/shared_flat_add_library.c	(revision 0)
@@ -0,0 +1,47 @@
+/*
+ * 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;
+}


More information about the uClibc mailing list