summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2001-02-19 00:24:52 +0000
committerManuel Novoa III <mjn3@codepoet.org>2001-02-19 00:24:52 +0000
commitdfe2d42547de8197f850f3ff0dfdc3caa4682518 (patch)
tree0b2969dbdd6c65f1fb5832e25d28bffa9570084a /libc
parent438aac726283dfffa6a5cf84b4acf6df0250af94 (diff)
Create __uClibc_main to handle what can be done in C instead of each arch's
respective crt0.S. crt0.S should now only be responsible for setting things up to call __uClibc_main(argc, argv, envp), which will do any other necessary setup (setting global __environ, stdio init, etc), call main, and exit. This should ease both maintainance and porting.
Diffstat (limited to 'libc')
-rw-r--r--libc/misc/internals/Makefile2
-rw-r--r--libc/misc/internals/__uClibc_main.c80
-rw-r--r--libc/stdlib/abort.c9
-rw-r--r--libc/stdlib/atexit.c40
-rw-r--r--libc/sysdeps/linux/i386/crt0.S33
5 files changed, 114 insertions, 50 deletions
diff --git a/libc/misc/internals/Makefile b/libc/misc/internals/Makefile
index 863d32401..2f0496d9a 100644
--- a/libc/misc/internals/Makefile
+++ b/libc/misc/internals/Makefile
@@ -24,7 +24,7 @@ TOPDIR=../../
include $(TOPDIR)Rules.mak
LIBC=$(TOPDIR)libc.a
-CSRC=ultostr.c ltostr.c
+CSRC=ultostr.c ltostr.c __uClibc_main.c
ifeq ($(HAS_FLOATS),true)
CSRC += dtostr.c zoicheck.c
endif
diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c
new file mode 100644
index 000000000..088754ecc
--- /dev/null
+++ b/libc/misc/internals/__uClibc_main.c
@@ -0,0 +1,80 @@
+/*
+ * Manuel Novoa III Feb 2001
+ *
+ * __uClibc_main is the routine to be called by all the arch-specific
+ * versions of crt0.S in uClibc.
+ *
+ * It is meant to handle any special initialization needed by the library
+ * such as setting the global variable(s) __environ (environ) and
+ * initializing the stdio package. Using weak symbols, the latter is
+ * avoided in the static library case.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Prototypes.
+ */
+
+extern int main(int argc, char **argv, char **envp);
+
+void __uClibc_main(int argc, char **argv, char **envp)
+ __attribute__ ((__noreturn__));
+
+/*
+ * Define an empty function and use it as a weak alias for the stdio
+ * initialization routine. That way we don't pull in all the stdio
+ * code unless we need to. Similarly, do the same for __stdio_close_all
+ * so as not to include atexit unnecessarily.
+ *
+ * NOTE!!! This is only true for the _static_ case!!!
+ */
+
+void __uClibc_empty_func(void)
+{
+}
+
+ __attribute__ ((__weak__, __alias__("__uClibc_empty_func")))
+void __init_stdio(void);
+
+ __attribute__ ((__weak__, __alias__("__uClibc_empty_func")))
+void __stdio_close_all(void);
+
+typedef void (*vfuncp) (void);
+vfuncp __uClibc_cleanup = __stdio_close_all;
+
+/*
+ * Now for our main routine.
+ */
+
+void __uClibc_main(int argc, char **argv, char **envp)
+{
+ /*
+ * Initialize the global variable __environ.
+ */
+ __environ = envp;
+
+ /*
+ * Initialize stdio here. In the static library case, this will
+ * be bypassed if not needed because of the weak alias above.
+ */
+ __init_stdio();
+
+ /*
+ * Finally, invoke application's main and then exit.
+ */
+ exit(main(argc, argv, envp));
+}
+
+/*
+ * Declare the __environ global variable and create a weak alias environ.
+ */
+
+char **__environ = 0;
+
+__asm__(".weak environ;environ = __environ");
+
+
+
+
diff --git a/libc/stdlib/abort.c b/libc/stdlib/abort.c
index 23510e913..7b7d6bb50 100644
--- a/libc/stdlib/abort.c
+++ b/libc/stdlib/abort.c
@@ -25,8 +25,8 @@ Cambridge, MA 02139, USA. */
#include <signal.h>
#include <errno.h>
-typedef void (*vfuncp) ();
-extern vfuncp __cleanup;
+typedef void (*vfuncp) (void);
+extern vfuncp __uClibc_cleanup;
extern void _exit __P((int __status)) __attribute__ ((__noreturn__));
/* Cause an abnormal program termination with core-dump. */
@@ -38,8 +38,9 @@ void abort(void)
sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL);
}
- if (__cleanup)
- __cleanup();
+ if (__uClibc_cleanup) { /* Not already executing __uClibc_cleanup. */
+ __uClibc_cleanup();
+ }
while (1)
if (raise(SIGABRT))
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index c720d4e90..b18e7951d 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -4,45 +4,58 @@
*/
/*
- * Manuel Novoa III Dec 2000
+ * Dec 2000 Manuel Novoa III
*
- * Modifications:
* Made atexit handling conform to standards... i.e. no args.
* Removed on_exit since it did not match gnu libc definition.
* Combined atexit and __do_exit into one object file.
+ *
+ * Feb 2000 Manuel Novoa III
+ *
+ * Reworked file after addition of __uClibc_main.
+ * Changed name of __do_exit to atexit_handler.
+ * Changed name of __cleanup to __uClibc_cleanup.
+ * Moved declaration of __uClibc_cleanup to __uClibc_main
+ * where it is initialized with (possibly weak alias)
+ * __stdio_close_all.
*/
#include <stdlib.h>
#include <errno.h>
typedef void (*vfuncp) (void);
-extern vfuncp __cleanup;
+extern vfuncp __uClibc_cleanup;
#ifdef L_atexit
+extern void __stdio_close_all(void);
+
static vfuncp __atexit_table[__UCLIBC_MAX_ATEXIT];
static int __atexit_count = 0;
-static void __do_exit(void)
+static void atexit_handler(void)
{
- int count = __atexit_count - 1;
+ int count;
- __atexit_count = -1; /* ensure no more will be added */
- __cleanup = 0; /* Calling exit won't re-do this */
+ /*
+ * Guard against more functions being added and againt being reinvoked.
+ */
+ __uClibc_cleanup = 0;
/* In reverse order */
- for (; count >= 0; count--) {
+ for (count = __atexit_count ; count-- ; ) {
(*__atexit_table[count])();
}
+ __stdio_close_all();
}
int atexit(vfuncp ptr)
{
- if ((__atexit_count < 0) || (__atexit_count >= __UCLIBC_MAX_ATEXIT)) {
+ if ((__uClibc_cleanup == 0) || (__atexit_count >= __UCLIBC_MAX_ATEXIT)) {
errno = ENOMEM;
return -1;
}
if (ptr) {
- __cleanup = __do_exit;
+ __uClibc_cleanup = atexit_handler;
__atexit_table[__atexit_count++] = ptr;
}
return 0;
@@ -50,12 +63,11 @@ int atexit(vfuncp ptr)
#endif
#ifdef L_exit
-vfuncp __cleanup = 0;
-
void exit(int rv)
{
- if (__cleanup)
- __cleanup();
+ if (__uClibc_cleanup) { /* Not already executing __uClibc_cleanup. */
+ __uClibc_cleanup();
+ }
_exit(rv);
}
#endif
diff --git a/libc/sysdeps/linux/i386/crt0.S b/libc/sysdeps/linux/i386/crt0.S
index a87287bc3..79e0a6748 100644
--- a/libc/sysdeps/linux/i386/crt0.S
+++ b/libc/sysdeps/linux/i386/crt0.S
@@ -30,11 +30,7 @@ Cambridge, MA 02139, USA. */
NULL
*/
-.global __environ
.global _start
-.global exit
-.global main
-.global _start_exit
.text
_start:
@@ -73,30 +69,5 @@ _start:
sub %ebx,%ebx
int $0x80
- /* set up __environ */
- movl 8(%esp),%eax
- movl %eax,__environ
-
- /* Ok, now run main() */
- call main
- pushl %eax
- call exit
-
- /* Just in case _exit fails... We use int $0x80 for __exit(). */
- popl %ebx
- .align 4,0x90
-_start_exit:
- movl $1,%eax
- int $0x80
- jmp _start_exit
- .align 4,0x90
-_void_void_null_func:
- ret
-
-.data
-__environ:
- .long 0
-.weak environ
-.align 4
-environ = __environ
-
+ /* Ok, now run uClibc's main() -- shouldn't return */
+ call __uClibc_main