summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-10-01 05:30:25 +0000
committerEric Andersen <andersen@codepoet.org>2002-10-01 05:30:25 +0000
commitb58a631942341b6ccb62ab400e862f404e22dbbf (patch)
tree0c6e622729b6c98417a15c0b7c10279c17ca0038
parent351c1d9029844a97d2771da883fc2b432d5e1bd4 (diff)
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.
-rw-r--r--extra/gcc-uClibc/gcc-uClibc.c7
-rwxr-xr-xextra/scripts/get-needed-libgcc-objects.sh5
-rwxr-xr-xextra/scripts/initfini.pl2
-rw-r--r--ldso/ldso/arm/elfinterp.c3
-rw-r--r--ldso/ldso/dl-elf.c33
-rw-r--r--ldso/ldso/i386/elfinterp.c3
-rw-r--r--ldso/ldso/ldso.c38
-rw-r--r--ldso/ldso/readelflib1.c33
-rw-r--r--ldso/ldso/sh/boot1_arch.h11
-rw-r--r--ldso/ldso/sh/dl-startup.h11
-rw-r--r--ldso/ldso/sh/dl-sysdep.h7
-rw-r--r--ldso/ldso/sh/elfinterp.c11
-rw-r--r--ldso/ldso/sh/ld_sysdep.h7
-rw-r--r--ldso/ldso/sh/resolve.S29
-rw-r--r--libc/Makefile4
-rw-r--r--libc/misc/internals/__uClibc_main.c167
-rw-r--r--libc/sysdeps/linux/arm/crt0.S28
-rw-r--r--libc/sysdeps/linux/i386/crt0.S27
-rw-r--r--libc/sysdeps/linux/mips/crt0.S17
-rw-r--r--libc/sysdeps/linux/sh/crt0.S49
-rw-r--r--libpthread/Makefile17
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(<INITFINI>) {
$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 <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
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); \