Browse Source

This commit contains a patch from Stefan Allius <allius@atecom.com> to change
how uClibc handles _init and _fini, allowing shared lib constructors and
destructors to initialize things in the correct sequence. Stefan ported the SH
architecture. I then ported x86, arm, and mips. x86 and arm are working fine,
but I don't think I quite got things correct for mips.

Eric Andersen 21 years ago
parent
commit
b58a631942

+ 3 - 4
extra/gcc-uClibc/gcc-uClibc.c

@@ -122,7 +122,7 @@ int main(int argc, char **argv)
 	int use_build_dir = 0, linking = 1, use_static_linking = 0;
 	int use_stdinc = 1, use_nostdinc_plus = 0, use_start = 1, use_stdlib = 1, use_pic = 0;
 	int source_count = 0, use_rpath = 0, verbose = 0;
-	int ctor_dtor = 0, cplusplus = 0;
+	int ctor_dtor = 1, cplusplus = 0;
 	int i, j, k, l, m, n;
 	char ** gcc_argv;
 	char ** gcc_argument;
@@ -165,7 +165,6 @@ int main(int argc, char **argv)
 		GPLUSPLUS_BIN[len-1]='+';
 		GPLUSPLUS_BIN[len-2]='+';
 	    }
-	    ctor_dtor = 1;
 	    cplusplus = 1;
 	    use_nostdinc_plus = 1;
 	}
@@ -307,8 +306,8 @@ int main(int argc, char **argv)
 					} else if (strcmp("--uclibc-use-rpath",argv[i]) == 0) {
 					    use_rpath = 1;
 					    argv[i]='\0';
-					} else if (strcmp("--uclibc-ctors",argv[i]) == 0) {
-					    ctor_dtor = 1;
+					} else if (strcmp("--uclibc-no-ctors",argv[i]) == 0) {
+					    ctor_dtor = 0;
 					    argv[i]='\0';
 					}
 					break;

+ 4 - 1
extra/scripts/get-needed-libgcc-objects.sh

@@ -48,7 +48,9 @@ echo Extracting referenced libgcc.a objects ...
 
 rm -f obj.need.0
 touch obj.need.0
-while [ -s obj.need ] && ! cmp -s obj.need obj.need.0 ; do
+
+cmp -s obj.need obj.need.0 ; state=$?
+while [ -s obj.need ] && [ $state -ne 0 ] ; do
     (cd tmp-gcc && cat ../obj.need | sort | uniq | xargs $LD -r -o ../libgcc.ldr)
     cp obj.need obj.need.0
     if $NM --undefined-only libgcc.ldr > sym.need ; then
@@ -58,6 +60,7 @@ while [ -s obj.need ] && ! cmp -s obj.need obj.need.0 ; do
 	    fi
 	done
     fi
+    cmp -s obj.need obj.need.0 ; state=$?
 done
 
 cat obj.need | sort | uniq > obj.need.0

+ 1 - 1
extra/scripts/initfini.pl

@@ -84,7 +84,7 @@ while(<INITFINI>) {
 	$omitcrtn = 0;
 	next;
     }
-    if (/^i_am_not_a_leaf/) {
+    if (/i_am_not_a_leaf/) {
 	$discard = 1;
 	next;
     }

+ 1 - 2
ldso/ldso/arm/elfinterp.c

@@ -236,8 +236,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 		}
 		else if (res >0)
 		{
-			_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
-					_dl_progname, strtab + symtab[symtab_index].st_name);
+			_dl_dprintf(2, "can't resolve symbol\n");
 			goof += res;
 		}
 	  }

+ 17 - 16
ldso/ldso/dl-elf.c

@@ -318,16 +318,13 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 	Elf32_Dyn *dpnt;
 	struct elf_resolve *tpnt;
 	elf_phdr *ppnt;
-	int piclib;
 	char *status;
-	int flags;
 	char header[4096];
 	unsigned long dynamic_info[24];
 	unsigned long *lpnt;
 	unsigned long libaddr;
 	unsigned long minvma = 0xffffffff, maxvma = 0;
-	int i;
-	int infile;
+	int i, flags, piclib, infile;
 
 	/* If this file is already loaded, skip this step */
 	tpnt = _dl_check_hashed_files(libname);
@@ -544,28 +541,32 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 #if defined(__mips__)
 	{
 		
-		int i = 1;
+		int indx = 1;
 		Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr;
 
 		while(dpnt->d_tag) {
 			dpnt++;
-			i++;
+			indx++;
 		}
-		dynamic_size = i;
+		dynamic_size = indx;
 	}
 #endif
 
-	for (i = 0; i < dynamic_size; i++) 
 	{
-		if (dpnt->d_tag > DT_JMPREL) {
+		unsigned long indx;
+
+		for (indx = 0; indx < dynamic_size; indx++) 
+		{
+			if (dpnt->d_tag > DT_JMPREL) {
+				dpnt++;
+				continue;
+			}
+			dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+			if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
+				dynamic_info[DT_TEXTREL] = 1;
 			dpnt++;
-			continue;
-		}
-		dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
-		if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
-			dynamic_info[DT_TEXTREL] = 1;
-		dpnt++;
-	};
+		};
+	}
 
 	/* If the TEXTREL is set, this means that we need to make the pages
 	   writable before we perform relocations.  Do this now. They get set

+ 1 - 2
ldso/ldso/i386/elfinterp.c

@@ -230,8 +230,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 		}
 		else if (res >0)
 		{
-			_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
-					_dl_progname, strtab + symtab[symtab_index].st_name);
+			_dl_dprintf(2, "can't resolve symbol\n");
 			goof += res;
 		}
 	  }

+ 30 - 8
ldso/ldso/ldso.c

@@ -303,12 +303,12 @@ LD_BOOT(unsigned long args)
   __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got));
 #elif defined(__sh__)
   __asm__(
-"	   mov.l    1f, %0"
-"	   mova     1f, r0"
-"	   bra      2f"
-"	   add r0,  %0"
-"	   .balign  4"
-"1:	   .long    _GLOBAL_OFFSET_TABLE_"
+"       mov.l    1f, %0\n"
+"       mova     1f, r0\n"
+"       bra      2f\n"
+"       add r0,  %0\n"
+"       .balign  4\n"
+"1:     .long    _GLOBAL_OFFSET_TABLE_\n"
 "2:" : "=r" (got) : : "r0");
 #elif defined(__cris__)
   __asm__("\tmove.d $pc,%0\n\tsub.d .:GOTOFF,%0\n\t":"=r"(got));
@@ -629,6 +629,13 @@ LD_BOOT(unsigned long args)
 	START();
 }
 
+#if defined (SUPPORT_LD_DEBUG)
+static void debug_fini (int status, void *arg)
+{
+	(void)status;
+	_dl_dprintf(_dl_debug_file,"\ncalling fini: %s\n\n", (const char*)arg);
+}
+#endif    
 
 static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt, 
 		unsigned long load_addr, unsigned long *hash_addr, Elf32_auxv_t auxvt[AT_EGID + 1], 
@@ -642,7 +649,9 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 	struct elf_resolve *tpnt1;
 	unsigned long brk_addr, *lpnt;
 	int (*_dl_atexit) (void *);
-
+#if defined (SUPPORT_LD_DEBUG)
+	int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*);
+#endif
 
 	/* Now we have done the mandatory linking of some things.  We are now
 	   free to start using global variables, since these things have all been
@@ -1196,6 +1205,10 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 	}
 #endif
 	_dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", NULL, NULL, symbolrel);
+#if defined (SUPPORT_LD_DEBUG)
+	_dl_on_exit = (int (*)(void (*)(int, void *),void*)) 
+		(intptr_t) _dl_find_hash("on_exit", NULL, NULL, symbolrel);
+#endif
 
 	/*
 	 * OK, fix one more thing - set up the debug_addr structure to point
@@ -1246,6 +1259,12 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 		}
 		if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) {
 			(*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+#if defined (SUPPORT_LD_DEBUG)
+			if(_dl_debug && _dl_on_exit)
+			{
+				(*_dl_on_exit)(debug_fini, tpnt->libname);
+			}
+#endif
 		}
 #ifdef LD_DEBUG
 		else {
@@ -1318,7 +1337,10 @@ int _dl_fixup(struct elf_resolve *tpnt)
 					tpnt->dynamic_info[DT_PLTRELSZ], 0);
 	}
 #if defined (SUPPORT_LD_DEBUG)
-	if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s; finished\n\n", tpnt->libname);	
+	if(_dl_debug) {
+		_dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);     
+		_dl_dprintf(_dl_debug_file,"; finished\n\n");
+	}
 #endif    
 	return goof;
 }

+ 17 - 16
ldso/ldso/readelflib1.c

@@ -318,16 +318,13 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 	Elf32_Dyn *dpnt;
 	struct elf_resolve *tpnt;
 	elf_phdr *ppnt;
-	int piclib;
 	char *status;
-	int flags;
 	char header[4096];
 	unsigned long dynamic_info[24];
 	unsigned long *lpnt;
 	unsigned long libaddr;
 	unsigned long minvma = 0xffffffff, maxvma = 0;
-	int i;
-	int infile;
+	int i, flags, piclib, infile;
 
 	/* If this file is already loaded, skip this step */
 	tpnt = _dl_check_hashed_files(libname);
@@ -544,28 +541,32 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 #if defined(__mips__)
 	{
 		
-		int i = 1;
+		int indx = 1;
 		Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr;
 
 		while(dpnt->d_tag) {
 			dpnt++;
-			i++;
+			indx++;
 		}
-		dynamic_size = i;
+		dynamic_size = indx;
 	}
 #endif
 
-	for (i = 0; i < dynamic_size; i++) 
 	{
-		if (dpnt->d_tag > DT_JMPREL) {
+		unsigned long indx;
+
+		for (indx = 0; indx < dynamic_size; indx++) 
+		{
+			if (dpnt->d_tag > DT_JMPREL) {
+				dpnt++;
+				continue;
+			}
+			dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
+			if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
+				dynamic_info[DT_TEXTREL] = 1;
 			dpnt++;
-			continue;
-		}
-		dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
-		if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
-			dynamic_info[DT_TEXTREL] = 1;
-		dpnt++;
-	};
+		};
+	}
 
 	/* If the TEXTREL is set, this means that we need to make the pages
 	   writable before we perform relocations.  Do this now. They get set

+ 5 - 6
ldso/ldso/sh/boot1_arch.h

@@ -7,15 +7,14 @@ asm("\
 	.globl	_dl_boot
 _dl_boot:
         mov	r15, r4
-        mov.l	.L_dl_boot2, r1
-	mova	.L_dl_boot2, r0
-	add	r1, r0
-	jsr	@r0
-	 add	#4, r4
+	mov.l   .L_dl_boot2, r0
+	bsrf    r0
+	add	#4, r4
+.jmp_loc:
 	jmp	@r0
 	 mov    #0, r4        /* call _start with arg == 0 */
 .L_dl_boot2:\n\
-	.long	_dl_boot2-.\n\
+	.long   _dl_boot2-.jmp_loc\n\
 	.previous\n\
 ");
 

+ 5 - 6
ldso/ldso/sh/dl-startup.h

@@ -7,15 +7,14 @@ asm("\
 	.globl	_dl_boot
 _dl_boot:
         mov	r15, r4
-        mov.l	.L_dl_boot2, r1
-	mova	.L_dl_boot2, r0
-	add	r1, r0
-	jsr	@r0
-	 add	#4, r4
+	mov.l   .L_dl_boot2, r0
+	bsrf    r0
+	add	#4, r4
+.jmp_loc:
 	jmp	@r0
 	 mov    #0, r4        /* call _start with arg == 0 */
 .L_dl_boot2:\n\
-	.long	_dl_boot2-.\n\
+	.long   _dl_boot2-.jmp_loc\n\
 	.previous\n\
 ");
 

+ 4 - 3
ldso/ldso/sh/dl-sysdep.h

@@ -34,13 +34,14 @@
 #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)		\
 	switch(ELF32_R_TYPE((RELP)->r_info)){			\
 	case R_SH_REL32:					\
-		*(REL) += (RELP)->r_addend - (LOAD);		\
+		*(REL)  = (SYMBOL) + (RELP)->r_addend		\
+			    - (unsigned long)(REL);		\
 		break;						\
 	case R_SH_DIR32:					\
-		*(REL) += (SYMBOL) + (RELP)->r_addend;		\
+		*(REL)  = (SYMBOL) + (RELP)->r_addend;		\
 		break;						\
 	case R_SH_RELATIVE:					\
-		*(REL) += (LOAD);				\
+		*(REL)  = (LOAD) + (RELP)->r_addend;		\
 		break;						\
 	case R_SH_NONE:						\
 		break;						\

+ 5 - 6
ldso/ldso/sh/elfinterp.c

@@ -236,8 +236,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 		}
 		else if (res >0)
 		{
-			_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
-					_dl_progname, strtab + symtab[symtab_index].st_name);
+			_dl_dprintf(2, "can't resolve symbol\n");
 			goof += res;
 		}
 	  }
@@ -289,17 +288,17 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 			/* handled later on */
 			break;
 		case R_SH_DIR32:
-			*reloc_addr += symbol_addr + rpnt->r_addend;
+			*reloc_addr = symbol_addr + rpnt->r_addend;
 			break;
 		case R_SH_JMP_SLOT:
 			*reloc_addr = symbol_addr + rpnt->r_addend;
 			break;
 		case R_SH_REL32:
-			*reloc_addr += rpnt->r_addend -
-					(unsigned long) tpnt->loadaddr;
+			*reloc_addr = symbol_addr + rpnt->r_addend -
+					(unsigned long) reloc_addr;
 			break;
 		case R_SH_RELATIVE:
-			*reloc_addr += (unsigned long) tpnt->loadaddr;
+			*reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
 			break;
 		default:
 			return -1; /*call _dl_exit(1) */

+ 4 - 3
ldso/ldso/sh/ld_sysdep.h

@@ -34,13 +34,14 @@
 #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)		\
 	switch(ELF32_R_TYPE((RELP)->r_info)){			\
 	case R_SH_REL32:					\
-		*(REL) += (RELP)->r_addend - (LOAD);		\
+		*(REL)  = (SYMBOL) + (RELP)->r_addend		\
+			    - (unsigned long)(REL);		\
 		break;						\
 	case R_SH_DIR32:					\
-		*(REL) += (SYMBOL) + (RELP)->r_addend;		\
+		*(REL)  = (SYMBOL) + (RELP)->r_addend;		\
 		break;						\
 	case R_SH_RELATIVE:					\
-		*(REL) += (LOAD);				\
+		*(REL)  = (LOAD) + (RELP)->r_addend;		\
 		break;						\
 	case R_SH_NONE:						\
 		break;						\

+ 22 - 7
ldso/ldso/sh/resolve.S

@@ -3,6 +3,7 @@
  */
 
 	.text
+	.globl	_dl_linux_resolver
 	.globl	_dl_linux_resolve
 	.type	_dl_linux_resolve, @function
 	.balign	16
@@ -31,13 +32,27 @@ _dl_linux_resolve:
 	fmov.s	fr4, @-r15
 #endif
 	sts.l	pr, @-r15
+/* Note - The PLT entries have been "optimised" not to use r2.  r2 is used by
+   GCC to return the address of large structures, so it should not be
+   corrupted here.  This does mean however, that those PLTs does not conform
+   to the SH PIC ABI.  That spec says that r0 contains the type of the PLT
+   and r2 contains the GOT id.  The GNU Plt version stores the GOT id in r0 and
+   ignores the type.  We can easily detect this difference however,
+   since the type will always be 0 or 8, and the GOT ids will always be
+   greater than or equal to 12.
 
-	mov	r2, r4		! link map address
-
-	mov.l	3f, r0
-	jsr	@r0		! Call resolver
-	 mov	r1, r5		! Reloc offset
-
+   Found in binutils/bfd/elf32-sh.c by Stefan Allius <allius@atecom.com>
+ */
+	mov     #8 ,r5
+	cmp/gt  r5, r0
+	bt      1f
+	mov     r2, r0          ! link map address in r2 (SH PIC ABI)
+1:
+	mov     r0, r4          ! link map address in r0 (GNUs PLT)
+	mov.l   3f, r5
+	bsrf    r5
+	mov	r1, r5		! Reloc offset
+.jmp_loc:
 	lds.l	@r15+, pr	! Get register content back
 
 #ifdef HAVE_FPU
@@ -64,6 +79,6 @@ _dl_linux_resolve:
 
 	.balign	4
 3:
-	.long	_dl_linux_resolver
+	.long   _dl_linux_resolver - .jmp_loc
 	.size	_dl_linux_resolve, . - _dl_linux_resolve
 

+ 2 - 2
libc/Makefile

@@ -53,9 +53,9 @@ shared: $(TOPDIR)lib/$(LIBNAME)
 		/bin/sh $(TOPDIR)../extra/scripts/get-needed-libgcc-objects.sh)
 	$(LD) $(LDFLAGS) $(VERSION_SCRIPT) -soname=$(SHARED_MAJORNAME) -o $(SHARED_FULLNAME) \
 		--whole-archive ./tmp/libgcc-need.a $(LIBNAME) --no-whole-archive \
-		$(TOPDIR)/libc/misc/internals/interp.o \
+		-init __uClibc_init $(TOPDIR)/libc/misc/internals/interp.o \
 		$(LIBGCC)
-	@/bin/true #rm -rf tmp
+	@true #rm -rf tmp
 	install -d $(TOPDIR)lib
 	rm -f $(TOPDIR)lib/$(SHARED_FULLNAME)
 	install -m 644 $(SHARED_FULLNAME) $(TOPDIR)lib

+ 111 - 56
libc/misc/internals/__uClibc_main.c

@@ -20,8 +20,6 @@
  * Prototypes.
  */
 extern int  main(int argc, char **argv, char **envp);
-extern void weak_function _init(void);
-extern void weak_function _fini(void);
 extern void weak_function _stdio_init(void);
 extern int *weak_const_function __errno_location(void);
 extern int *weak_const_function __h_errno_location(void);
@@ -36,10 +34,11 @@ extern void weak_function __pthread_initialize_minimal(void);
 
 
 
+
 /*
  * Declare the __environ global variable and create a weak alias environ.
- * Note: Apparently we must initialize __environ for the weak environ
- * symbol to be included.
+ * Note: Apparently we must initialize __environ to ensure that the weak 
+ * environ symbol is also included.
  */
 
 char **__environ = 0;
@@ -47,68 +46,124 @@ weak_alias(__environ, environ);
 
 
 
+/* __uClibc_init completely initialize uClibc so it is ready to use.
+ *
+ * On ELF systems (with a dynamic loader) this function must be called
+ * from the dynamic loader (see TIS and ELF Specification), so that
+ * constructors of shared libraries (which depend on libc) can use all
+ * the libc code without restriction.  For this we link the shared
+ * version of the uClibc with -init __uClibc_init so DT_INIT for
+ * uClibc is the address of __uClibc_init
+ * 
+ * In all other cases we call it from the main stub
+ * __uClibc_start_main.
+ */
 
-void __attribute__ ((__noreturn__)) 
-__uClibc_main(int argc, char **argv, char **envp) 
+void __uClibc_init(void) 
 {
-	/* If we are dynamically linked the shared lib loader
-	 * already did this for us.  But if we are statically
-	 * linked, we need to do this for ourselves. */
-	if (__environ==NULL) {
-		/* Statically linked. */ 
-		__environ = envp;
-	}
+    static int been_there_done_that = 0;
+
+    if (been_there_done_that) 
+	return;
+    been_there_done_that++;
 
 #ifdef __UCLIBC_HAS_THREADS__
-	if (likely(__pthread_initialize_minimal!=NULL))
-	    __pthread_initialize_minimal();
+    /* Before we start initialzing uClibc we have to call
+     * __pthread_initialize_minimal so we can use pthread_locks 
+     * whenever they are needed.
+     */
+    if (likely(__pthread_initialize_minimal!=NULL))
+	__pthread_initialize_minimal();
 #endif
 
 #if 0
-	/* Some security at this point.  Prevent starting a SUID binary
-	 * where the standard file descriptors are not opened.  We have
-	 * to do this only for statically linked applications since
-	 * otherwise the dynamic loader did the work already.  */
-	if (unlikely (__libc_enable_secure!=NULL))
-		__libc_check_standard_fds ();
+    /* Some security at this point.  Prevent starting a SUID binary
+     * where the standard file descriptors are not opened.  We have
+     * to do this only for statically linked applications since
+     * otherwise the dynamic loader did the work already.  */
+    if (unlikely (__libc_enable_secure!=NULL))
+	__libc_check_standard_fds ();
 #endif
 
 #ifdef __UCLIBC_HAS_LOCALE__
-	/* Initialize the global locale structure. */
-	if (likely(_locale_init!=NULL))
-	    _locale_init();
+    /* Initialize the global locale structure. */
+    if (likely(_locale_init!=NULL))
+	_locale_init();
 #endif
 
-	/*
-	 * Initialize stdio here.  In the static library case, this will
-	 * be bypassed if not needed because of the weak alias above.
-	 */
-	if (likely(_stdio_init != NULL))
-		_stdio_init();
-
-	/* Arrange for dtors to run at exit.  */
-	if (likely(_fini!=NULL && atexit)) {
-		atexit (&_fini);
-	}
-
-	/* Run all ctors now.  */
-	if (likely(_init!=NULL))
-		_init();
-
-	/*
-	 * Note: It is possible that any initialization done above could
-	 * have resulted in errno being set nonzero, so set it to 0 before
-	 * we call main.
-	 */
-	if (likely(__errno_location!=NULL))
-		*(__errno_location()) = 0;
-
-	/* Set h_errno to 0 as well */
-	if (likely(__h_errno_location!=NULL))
-		*(__h_errno_location()) = 0;
-
-	/*
-	 * Finally, invoke application's main and then exit.
-	 */
-	exit(main(argc, argv, envp));
+    /*
+     * Initialize stdio here.  In the static library case, this will
+     * be bypassed if not needed because of the weak alias above.
+     */
+    if (likely(_stdio_init != NULL))
+	_stdio_init();
+
+}
+
+
+/* __uClibc_start_main is the new main stub for uClibc. This function is 
+ * called from crt0 (version 0.9.16 or newer), after ALL shared libraries 
+ * are initialized, just before we call the application's main function.
+ */
+void __attribute__ ((__noreturn__)) 
+__uClibc_start_main(int argc, char **argv, char **envp, 
+	void (*app_init)(void), void (*app_fini)(void))
+{
+
+    /* If we are dynamically linked the shared lib loader already
+     * did this for us.  But if we are statically linked, we need
+     * to do this for ourselves.  */
+    if (__environ==NULL) {
+	/* Statically linked. */ 
+	__environ = envp;
+    }
+
+    /* We need to initialize uClibc.  If we are dynamically linked this
+     * may have already been completed by the shared lib loader.  We call 
+     * __uClibc_init() regardless, to be sure the right thing happens. */
+    __uClibc_init();
+
+    /* Arrange for the application's dtors to run before we exit.  */
+    if (app_fini!=NULL && atexit) {
+	atexit (app_fini);
+    }
+
+    /* Run all the application's ctors now.  */
+    if (app_init!=NULL) {
+	app_init();
+    }
+
+    /* Note: It is possible that any initialization done above could
+     * have resulted in errno being set nonzero, so set it to 0 before
+     * we call main.
+     */
+    if (likely(__errno_location!=NULL))
+	*(__errno_location()) = 0;
+
+    /* Set h_errno to 0 as well */
+    if (likely(__h_errno_location!=NULL))
+	*(__h_errno_location()) = 0;
+
+    /*
+     * Finally, invoke application's main and then exit.
+     */
+    exit(main(argc, argv, envp));
+}
+
+
+/* __uClibc_main is the old main stub of the uClibc. This
+ * function is called from crt0 (uClibc 0.9.15 and older) after
+ * ALL shared libraries are initialized, and just before we call
+ * the application's main() function.  
+ *
+ * Attention: This stub does not call the .init/.fini sections of
+ * the application. If you need this, please fix your uClibc port
+ * so that  __uClibc_start_main is called by your crt0.S with
+ * _init and _fini properly set.
+*/
+void __attribute__ ((__noreturn__)) 
+__uClibc_main(int argc, char **argv, char ** envp)
+{
+    __uClibc_start_main(argc, argv, envp, NULL, NULL);
 }
+

+ 15 - 13
libc/sysdeps/linux/arm/crt0.S

@@ -50,20 +50,10 @@ ARM register quick reference:
 
 .text
 	.global _start
-	.global __uClibc_main
-
 	.type   _start,%function
-	.type   __uClibc_main,%function
 
 .text
 _start:
-#if 0 /* some old code the I feel should not be here - davidm */
-	@ adjust the data segment base pointer
-	ldr r3,=__data_start
-	sub sl,sl,r3
-	mov BASEREG,sl
-#endif
-
 	/* clear the frame pointer */
 	mov     fp, #0
 
@@ -78,10 +68,11 @@ _start:
 	   we find there (hopefully the environment) in r2 */
 	add     r2, r1, r0, lsl #2
 	add     r2, r2, #4
+
 #else
 	/*
-	 * uClinux stacks look a little different to MMU stacks
-	 * for no good reason
+	 * uClinux stacks look a little different from normal
+	 * MMU-full Linux stacks (for no good reason)
 	 */
 	/* pull argc, argv and envp off the stack */
 	ldr r0,[sp, #0]
@@ -89,8 +80,19 @@ _start:
 	ldr r2,[sp, #8]
 #endif
 
+	/* Store the address of _init in r3 as an argument to main() */
+	ldr r3, =_init
+
+	/* Push _fini onto the stack as the final argument to main() */
+	stmfd sp!, {r0}
+	ldr a1, =_fini
+	stmfd sp!, {r0}
+
 	/* Ok, now run uClibc's main() -- shouldn't return */
-	bl	__uClibc_main
+	bl	__uClibc_start_main
+
+	/* Crash if somehow `exit' returns anyways.  */
+	bl abort
 
 /* Stick in a dummy reference to main(), so that if an application
  * is linking when the main() function is in a static library (.a)

+ 12 - 15
libc/sysdeps/linux/i386/crt0.S

@@ -33,11 +33,11 @@ Cambridge, MA 02139, USA.  */
 .text
 	.align 4
 
-.globl _start
-	.type	 _start,@function
+	.globl _start
+	.type _start,@function
 
 _start:
-	/* First locate the start of the environment variables */
+	/* locate the start of the environment variables */
 	popl %ecx	/* Store argc into %ecx */
 	movl %esp,%ebx  /* Store argv into ebx */
 	movl %esp,%eax  /* Store argv into eax as well*/
@@ -52,7 +52,6 @@ _start:
 	    %eax = env	    ; argv + (argc * 4) + 4
 	*/
 
-
 	/* Set up an invalid (NULL return address, NULL frame pointer)
 	   callers stack frame so anybody unrolling the stack knows where
 	   to stop */
@@ -62,20 +61,18 @@ _start:
 	pushl %ebp      /* callers %ebp (frame pointer) */
 	movl %esp,%ebp  /* mark callers stack frame as invalid */
 
-	/* Now set the environment, argc, and argv where the app can get to them */
-	pushl %eax      /* Environment pointer */
-	pushl %ebx       /* Argument pointer */
-	pushl %ecx      /* And the argument count */
+	/* Push .init and .fini arguments to __uClibc_start_main() on the stack */
+	pushl $_fini
+	pushl $_init
 
-#if 0
-	/* Make sure we are not using iBCS2 personality. (i.e. force linux).  */
-	movl $136,%eax
-	sub %ebx,%ebx
-	int $0x80
-#endif
+	/* Push envp, argc, and argc arguments to __uClibc_start_main() on the stack */ 
+	pushl %eax	/* Environment pointer */
+	pushl %ebx	/* Argument pointer */
+	pushl %ecx	/* And the argument count */
 
 	/* Ok, now run uClibc's main() -- shouldn't return */
-	call __uClibc_main
+	call __uClibc_start_main
+
 	/* Crash if somehow `exit' returns anyways.  */
 	hlt
 

+ 15 - 2
libc/sysdeps/linux/mips/crt0.S

@@ -30,9 +30,22 @@ __start:
 	addu a2, a0, 1	    /* load envp */
         sll  a2, a2, 2
 	add  a2, a2, a1
+
+	/* Store the address of _init in a3 as an argument to __uClibc_start_main() */
+	la   a3, _init
+
+	/* Push _fini onto the stack as the final argument to __uClibc_start_main()
+	    I don't think I am doing this properly but it at least compiles... 
+	*/
+	la   t0, _fini
+	sw   t0,16(sp)
+	
 	/* Ok, now run uClibc's main() -- shouldn't return */
-	jal	__uClibc_main
-	hlt:    b hlt                   /* Crash if somehow it does return.  */
+	jal  __uClibc_start_main
+
+	/* Crash if somehow `exit' returns anyways.  */
+hlt:
+	b   hlt
 
 /* Stick in a dummy reference to main(), so that if an application
  * is linking when the main() function is in a static library (.a)

+ 30 - 19
libc/sysdeps/linux/sh/crt0.S

@@ -26,13 +26,6 @@
 
 	At this entry point, most registers' values are unspecified, except:
 
-   r4		Contains a function pointer to be registered with `atexit'.
-   		This is how the dynamic linker arranges to have DT_FINI
-		functions called for shared libraries that have been loaded
-		before this code runs.
-		WARNING: At that stage only static linker is supported. For
-		uCLinux we won't bother with r4.
-
    sp		The stack contains the arguments and environment:
    		0(sp)			argc
 		4(sp)			argv[0]
@@ -42,18 +35,26 @@
 		...
 					NULL
 */
+	.file "crt0.S"
 	.text
 	.globl _start
 	.type _start,@function
 	.size _start,_start_end - _start
 _start:
-	/* Clear the frame pointer since this is the outermost frame. (in delay slot) */
+	/* Clear the frame pointer since this is the outermost frame. */
 	mov #0, r14
 
 	/* Pop argc off the stack and save a pointer to argv */
 	mov.l @r15+,r4
 	mov r15, r5
 
+	/* Push the finip argument to __uClibc_start_main() onto the stack */
+	mov.l L_fini,r6
+	mov.l r6,@-r15
+
+	/* Setup the value for the initp argument */
+	mov.l L_init, r7
+
 	/*
 	 * Setup the value for the environment pointer:
 	 * r6 = (argc + 1) * 4
@@ -62,27 +63,39 @@ _start:
 	mov r4,r6
 	add #1,r6
 	shll2 r6
-	add r5,r6
 
-	/* call main */
+	/* jump to __uClibc_start_main (argc, argv, envp, app_init, app_fini) */
 	mov.l L_main, r0
 	jsr @r0
-	nop /* delay slot */
-
+	add r5, r6  /* delay slot */
 	/* We should not get here. */
 	mov.l L_abort, r0
-	jsr @r0
-	nop /* delay slot */
+	jmp @r0
+	nop
 
 _start_end:	
 	.align	2
 
+	.weak   _init
+	.type   _init,@function
+_init:
+	rts
+	nop
+
+.Lfe1:
+	.size   _init,.Lfe1-_init
+	.weak   _fini
+	.set    _fini,_init
 
 L_main:
-	.long	__uClibc_main
+	.long   __uClibc_start_main /* in libuClibc.*.so */
 
-L_abort:
-	.long	abort
+L_init:
+      .long   _init
+L_fini:
+      .long   _fini
+L_abort: 
+      .long   abort   
 
 /* Stick in a dummy reference to main(), so that if an application
  * is linking when the main() function is in a static library (.a)
@@ -90,5 +103,3 @@ L_abort:
 L_dummy_main_reference:
 	.long	main
 
-	.data
-

+ 13 - 4
libpthread/Makefile

@@ -36,6 +36,15 @@ ifeq ($(strip $(DODEBUG)),true)
 endif
 endif
 
+GCC_LIB_DIR = $(dir $(shell $(CC) -print-libgcc-file-name ))
+ifeq ($(strip $(DOPIC)),true)
+    START_FILES  = $(TOPDIR)lib/crti.o     $(GCC_LIB_DIR)crtbeginS.o
+    END_FILES    = $(GCC_LIB_DIR)crtendS.o $(TOPDIR)lib/crtn.o
+else
+    START_FILES  = $(TOPDIR)lib/crti.o    $(GCC_LIB_DIR)crtbegin.o
+    END_FILES    = $(GCC_LIB_DIR)crtend.o $(TOPDIR)lib/crtn.o
+endif
+
 ALL_SUBDIRS = linuxthreads linuxthreads_db
 
 all: $(LIBPTHREAD) $(LIBTHREAD_DB)
@@ -67,9 +76,9 @@ shared: all
 	if [ -f $(LIBPTHREAD) ] ; then \
 		set -e; \
 		$(LD) $(LDFLAGS) -soname=$(LIBPTHREAD_SHARED).$(MAJOR_VERSION) \
-			-o $(LIBPTHREAD_SHARED_FULLNAME) --whole-archive $(LIBPTHREAD) \
+			-o $(LIBPTHREAD_SHARED_FULLNAME) $(START_FILES) --whole-archive $(LIBPTHREAD) \
 			--no-whole-archive $(TOPDIR)/libc/misc/internals/interp.o \
-			-L$(TOPDIR)/lib -lc; \
+			-L$(TOPDIR)/lib -lc $(END_FILES); \
 		install -d $(TOPDIR)lib; \
 		rm -f $(TOPDIR)lib/$(LIBPTHREAD_SHARED_FULLNAME) \
 			$(TOPDIR)lib/$(LIBPTHREAD_SHARED).$(MAJOR_VERSION); \
@@ -82,9 +91,9 @@ shared: all
 	if [ -f $(LIBTHREAD_DB) ] ; then \
 		set -e; \
 		$(LD) $(LDFLAGS) -soname=$(LIBTHREAD_DB_SHARED).$(MAJOR_VERSION) \
-			-o $(LIBTHREAD_DB_SHARED_FULLNAME) --whole-archive $(LIBTHREAD_DB) \
+			-o $(LIBTHREAD_DB_SHARED_FULLNAME) $(START_FILES) --whole-archive $(LIBTHREAD_DB) \
 			--no-whole-archive $(TOPDIR)/libc/misc/internals/interp.o \
-			-L$(TOPDIR)/lib -lc; \
+			-L$(TOPDIR)/lib -lc $(END_FILES); \
 		install -d $(TOPDIR)lib; \
 		rm -f $(TOPDIR)lib/$(LIBTHREAD_DB_SHARED_FULLNAME) \
 			$(TOPDIR)lib/$(LIBTHREAD_DB_SHARED).$(MAJOR_VERSION); \