From b58a631942341b6ccb62ab400e862f404e22dbbf Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Tue, 1 Oct 2002 05:30:25 +0000 Subject: This commit contains a patch from Stefan Allius 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. --- extra/gcc-uClibc/gcc-uClibc.c | 7 +- extra/scripts/get-needed-libgcc-objects.sh | 5 +- extra/scripts/initfini.pl | 2 +- ldso/ldso/arm/elfinterp.c | 3 +- ldso/ldso/dl-elf.c | 33 +++--- ldso/ldso/i386/elfinterp.c | 3 +- ldso/ldso/ldso.c | 38 +++++-- ldso/ldso/readelflib1.c | 33 +++--- ldso/ldso/sh/boot1_arch.h | 11 +- ldso/ldso/sh/dl-startup.h | 11 +- ldso/ldso/sh/dl-sysdep.h | 7 +- ldso/ldso/sh/elfinterp.c | 11 +- ldso/ldso/sh/ld_sysdep.h | 7 +- ldso/ldso/sh/resolve.S | 29 +++-- libc/Makefile | 4 +- libc/misc/internals/__uClibc_main.c | 167 +++++++++++++++++++---------- libc/sysdeps/linux/arm/crt0.S | 28 ++--- libc/sysdeps/linux/i386/crt0.S | 27 +++-- libc/sysdeps/linux/mips/crt0.S | 17 ++- libc/sysdeps/linux/sh/crt0.S | 49 +++++---- libpthread/Makefile | 17 ++- 21 files changed, 317 insertions(+), 192 deletions(-) diff --git a/extra/gcc-uClibc/gcc-uClibc.c b/extra/gcc-uClibc/gcc-uClibc.c index f260b5ec2..13049d17d 100644 --- a/extra/gcc-uClibc/gcc-uClibc.c +++ b/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; diff --git a/extra/scripts/get-needed-libgcc-objects.sh b/extra/scripts/get-needed-libgcc-objects.sh index 5d81154b2..00cfab2a9 100755 --- a/extra/scripts/get-needed-libgcc-objects.sh +++ b/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 diff --git a/extra/scripts/initfini.pl b/extra/scripts/initfini.pl index 431b39396..41add5d88 100755 --- a/extra/scripts/initfini.pl +++ b/extra/scripts/initfini.pl @@ -84,7 +84,7 @@ while() { $omitcrtn = 0; next; } - if (/^i_am_not_a_leaf/) { + if (/i_am_not_a_leaf/) { $discard = 1; next; } diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c index 4f7e6bd3f..84b94550b 100644 --- a/ldso/ldso/arm/elfinterp.c +++ b/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; } } diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 4259a4292..199726ff3 100644 --- a/ldso/ldso/dl-elf.c +++ b/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 diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c index 2caaa2413..2d08bf406 100644 --- a/ldso/ldso/i386/elfinterp.c +++ b/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; } } diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index ff13675aa..b81c84092 100644 --- a/ldso/ldso/ldso.c +++ b/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; } diff --git a/ldso/ldso/readelflib1.c b/ldso/ldso/readelflib1.c index 4259a4292..199726ff3 100644 --- a/ldso/ldso/readelflib1.c +++ b/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 diff --git a/ldso/ldso/sh/boot1_arch.h b/ldso/ldso/sh/boot1_arch.h index 798121dc0..40d6a0dd4 100644 --- a/ldso/ldso/sh/boot1_arch.h +++ b/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\ "); diff --git a/ldso/ldso/sh/dl-startup.h b/ldso/ldso/sh/dl-startup.h index 798121dc0..40d6a0dd4 100644 --- a/ldso/ldso/sh/dl-startup.h +++ b/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\ "); diff --git a/ldso/ldso/sh/dl-sysdep.h b/ldso/ldso/sh/dl-sysdep.h index a0ff05fdb..cf8820e4e 100644 --- a/ldso/ldso/sh/dl-sysdep.h +++ b/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; \ diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c index 3e0bb87be..d94389ef7 100644 --- a/ldso/ldso/sh/elfinterp.c +++ b/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) */ diff --git a/ldso/ldso/sh/ld_sysdep.h b/ldso/ldso/sh/ld_sysdep.h index a0ff05fdb..cf8820e4e 100644 --- a/ldso/ldso/sh/ld_sysdep.h +++ b/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; \ diff --git a/ldso/ldso/sh/resolve.S b/ldso/ldso/sh/resolve.S index 4d8eee6c2..7fef6d77f 100644 --- a/ldso/ldso/sh/resolve.S +++ b/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 + */ + 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 diff --git a/libc/Makefile b/libc/Makefile index 401a56695..1809779d6 100644 --- a/libc/Makefile +++ b/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 diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 53f897d9f..aa4655cec 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/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); } + diff --git a/libc/sysdeps/linux/arm/crt0.S b/libc/sysdeps/linux/arm/crt0.S index 442c9e84b..dc0ec87d8 100644 --- a/libc/sysdeps/linux/arm/crt0.S +++ b/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) diff --git a/libc/sysdeps/linux/i386/crt0.S b/libc/sysdeps/linux/i386/crt0.S index 3623fe821..97f1fde63 100644 --- a/libc/sysdeps/linux/i386/crt0.S +++ b/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 diff --git a/libc/sysdeps/linux/mips/crt0.S b/libc/sysdeps/linux/mips/crt0.S index 6770ab0b1..7ff3b253f 100644 --- a/libc/sysdeps/linux/mips/crt0.S +++ b/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) diff --git a/libc/sysdeps/linux/sh/crt0.S b/libc/sysdeps/linux/sh/crt0.S index 10915d545..e74ae86c4 100644 --- a/libc/sysdeps/linux/sh/crt0.S +++ b/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 - diff --git a/libpthread/Makefile b/libpthread/Makefile index 7566b4753..7edf34f66 100644 --- a/libpthread/Makefile +++ b/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); \ -- cgit v1.2.3