diff options
Diffstat (limited to 'klibc/klibc/__shared_init.c')
-rw-r--r-- | klibc/klibc/__shared_init.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/klibc/klibc/__shared_init.c b/klibc/klibc/__shared_init.c new file mode 100644 index 0000000000..63e3f4644e --- /dev/null +++ b/klibc/klibc/__shared_init.c @@ -0,0 +1,56 @@ +/* + * __shared_init.c + * + * This function takes the raw data block set up by the ELF loader + * in the kernel and parses it. It is invoked by crt0.S which makes + * any necessary adjustments and passes calls this function using + * the standard C calling convention. + * + * The arguments are: + * uintptr_t *elfdata -- The ELF loader data block; usually from the stack. + * Basically a pointer to argc. + * void (*onexit)(void) -- Function to install into onexit + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdint.h> +#include <klibc/compiler.h> +#include <elf.h> + +char **environ; + +__noreturn __libc_init(uintptr_t *elfdata, void (*onexit)(void)) +{ + int argc; + char **argv, **envp, **envend; + struct auxentry { + uintptr_t type; + uintptr_t v; + } *auxentry; + typedef int (*main_t)(int, char **, char **); + main_t main_ptr = NULL; + + (void)onexit; /* For now, we ignore this... */ + + argc = (int)*elfdata++; + argv = (char **)elfdata; + envp = argv+(argc+1); + + /* The auxillary entry vector is after all the environment vars */ + for ( envend = envp ; *envend ; envend++ ); + auxentry = (struct auxentry *)(envend+1); + + while ( auxentry->type ) { + if ( auxentry->type == AT_ENTRY ) { + main_ptr = (main_t)(auxentry->v); + break; + } + auxentry++; + } + + environ = envp; + exit(main_ptr(argc, argv, envp)); +} + + |