From 91689649656314b04f3dbee0415a9254eb1424dd Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Thu, 23 Feb 2023 18:14:36 +0300 Subject: hurd: Generalize init-first.c to support x86_64 Signed-off-by: Sergey Bugaev Message-Id: <20230223151436.49180-2-bugaevc@gmail.com> --- sysdeps/mach/hurd/i386/init-first.c | 262 ----------------------------------- sysdeps/mach/hurd/x86/init-first.c | 268 ++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+), 262 deletions(-) delete mode 100644 sysdeps/mach/hurd/i386/init-first.c create mode 100644 sysdeps/mach/hurd/x86/init-first.c diff --git a/sysdeps/mach/hurd/i386/init-first.c b/sysdeps/mach/hurd/i386/init-first.c deleted file mode 100644 index 05424563bf..0000000000 --- a/sysdeps/mach/hurd/i386/init-first.c +++ /dev/null @@ -1,262 +0,0 @@ -/* Initialization code run first thing by the ELF startup code. For i386/Hurd. - Copyright (C) 1995-2023 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "hurdstartup.h" - -#include -#include -#include -#include - -extern void __mach_init (void); -extern void __init_misc (int, char **, char **); - -unsigned long int __hurd_threadvar_stack_offset; -unsigned long int __hurd_threadvar_stack_mask; - -extern int __libc_argc attribute_hidden; -extern char **__libc_argv attribute_hidden; -extern char **_dl_argv; - -#ifndef SHARED -unsigned short __init1_desc; -static tcbhead_t __init1_tcbhead; -#endif - -/* Things that want to be run before _hurd_init or much anything else. - Importantly, these are called before anything tries to use malloc. */ -DEFINE_HOOK (_hurd_preinit_hook, (void)); - - -/* We call this once the Hurd magic is all set up and we are ready to be a - Posixoid program. This does the same things the generic version does. */ -static void -posixland_init (int argc, char **argv, char **envp) -{ - /* Now we have relocations etc. we can start signals etc. */ - _hurd_libc_proc_init (argv); - -#ifdef SHARED - /* Make sure we don't initialize twice. */ - if (__libc_initial) - { - /* Set the FPU control word to the proper default value. */ - __setfpucw (__fpu_control); - } - else - { - /* Initialize data structures so the additional libc can do RPCs. */ - __mach_init (); - } -#else /* !SHARED */ - __setfpucw (__fpu_control); -#endif - - /* Save the command-line arguments. */ - __libc_argc = argc; - __libc_argv = argv; - __environ = envp; - -#ifndef SHARED - _dl_non_dynamic_init (); -#endif - __init_misc (argc, argv, envp); -} - -static void -init (void **data) -{ - int argc = (int) *data; - char **argv = (void *) (data + 1); - char **envp = &argv[argc + 1]; - struct hurd_startup_data *d; - - /* Since the cthreads initialization code uses malloc, and the - malloc initialization code needs to get at the environment, make - sure we can find it. We'll need to do this again later on since - switching stacks changes the location where the environment is - stored. */ - __environ = envp; - - while (*envp) - ++envp; - d = (void *) ++envp; - -#ifndef SHARED - - /* If we are the bootstrap task started by the kernel, - then after the environment pointers there is no Hurd - data block; the argument strings start there. */ - if ((void *) d == argv[0] || d->phdr == 0) - { - __libc_enable_secure = 0; - /* With a new enough linker (binutils-2.23 or better), - the magic __ehdr_start symbol will be available and - __libc_start_main will have done this that way already. */ - if (_dl_phdr == NULL) - { - /* We may need to see our own phdrs, e.g. for TLS setup. - Try the usual kludge to find the headers without help from - the exec server. */ - extern const void __executable_start; - const ElfW(Ehdr) *const ehdr = &__executable_start; - _dl_phdr = (const void *) ehdr + ehdr->e_phoff; - _dl_phnum = ehdr->e_phnum; - assert (ehdr->e_phentsize == sizeof (ElfW(Phdr))); - } - } - else - { - __libc_enable_secure = d->flags & EXEC_SECURE; - _dl_phdr = (ElfW(Phdr) *) d->phdr; - _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr)); - assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0); - } -#endif - - if ((void *) d == argv[0]) - return; - - _hurd_init_dtable = d->dtable; - _hurd_init_dtablesize = d->dtablesize; - - if (d->portarray || d->intarray) - /* Initialize library data structures, start signal processing, etc. */ - _hurd_init (d->flags, argv, - d->portarray, d->portarraysize, - d->intarray, d->intarraysize); -} - -/* Do the first essential initializations that must precede all else. */ -static inline void -first_init (void) -{ - /* Initialize data structures so we can do RPCs. */ - __mach_init (); - -#ifndef SHARED - /* In the static case, we need to set up TLS early so that the stack - protection guard can be read at gs:0x14 by the gcc-generated snippets. */ - _hurd_tls_init (&__init1_tcbhead); - asm ("movw %%gs,%w0" : "=m" (__init1_desc)); -#endif - - RUN_RELHOOK (_hurd_preinit_hook, ()); -} - -#ifdef SHARED -/* This function is called specially by the dynamic linker to do early - initialization of the shared C library before normal initializers - expecting a Posixoid environment can run. */ - -void -_dl_init_first (void *data) -{ - first_init (); - init (data); -} - -/* The regular posixland initialization is what goes into libc's - normal initializer. */ -/* NOTE! The linker notices the magical name `_init' and sets the DT_INIT - pointer in the dynamic section based solely on that. It is convention - for this function to be in the `.init' section, but the symbol name is - the only thing that really matters!! */ -strong_alias (posixland_init, _init); - -void -__libc_init_first (int argc, char **argv, char **envp) -{ - /* Everything was done in the shared library initializer, _init. */ -} - -#else /* SHARED */ - -strong_alias (posixland_init, __libc_init_first); - -/* XXX This is all a crock and I am not happy with it. - This poorly-named function is called by static-start.S, - which should not exist at all. */ -void -inhibit_stack_protector -_hurd_stack_setup (void) -{ - /* This is the very first C code that runs in a statically linked - executable -- calling this function is the first thing that _start in - static-start.S does. Once this function returns, the unusual way that it - does (see below), _start jumps to _start1, the regular start-up code. - - _start1 expects the arguments, environment, and a Hurd data block to be - located at the top of the stack. The data may already be located there, - or we may need to receive it from the exec server. */ - void *caller = __builtin_extract_return_addr (__builtin_return_address (0)); - /* If the arguments and environment are already located on the stack, this is - where they are, just above our call frame. Note that this may not be a - valid pointer in case we're supposed to receive the arguments from the exec - server, so we can not dereference it yet. */ - void **p = (void **) __builtin_frame_address (0) + 2; - - /* Init the essential things. */ - first_init (); - - void doinit (intptr_t *data) - { - init ((void **) data); - asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack. */ - "xorl %%ebp, %%ebp\n" /* Clear outermost frame pointer. */ - "jmp *%1" : : "r" (data), "r" (caller)); - __builtin_unreachable (); - } - - /* _hurd_startup () will attempt to receive the data block from the exec - server; or if that is not possible, will take the data from the pointer - we pass it here. The important point here is that the data - _hurd_startup () collects may be allocated in its stack frame (with - alloca), which is why _hurd_startup () does not return the normal way. - Instead, it invokes a callback (which is not expected to return normally - either). - - Our callback not only passes the data pointer to init (), but also jumps - out of the call stack back to our caller (i.e. to _start1), while setting - the stack pointer to the data (which is somewhere on the current stack - anyway). This way, _start1 find the data on the top of the stack, just as - it expects to. */ - _hurd_startup (p, &doinit); - __builtin_unreachable (); -} -#endif - - -/* This function is defined here so that if this file ever gets into - ld.so we will get a link error. Having this file silently included - in ld.so causes disaster, because the _init definition above will - cause ld.so to gain an init function, which is not a cool thing. */ - -void -_dl_start (void) -{ - abort (); -} diff --git a/sysdeps/mach/hurd/x86/init-first.c b/sysdeps/mach/hurd/x86/init-first.c new file mode 100644 index 0000000000..2fccaefdd2 --- /dev/null +++ b/sysdeps/mach/hurd/x86/init-first.c @@ -0,0 +1,268 @@ +/* Initialization code run first thing by the ELF startup code. For i386/Hurd. + Copyright (C) 1995-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "hurdstartup.h" + +#include +#include +#include +#include + +extern void __mach_init (void); +extern void __init_misc (int, char **, char **); + +unsigned long int __hurd_threadvar_stack_offset; +unsigned long int __hurd_threadvar_stack_mask; + +extern int __libc_argc attribute_hidden; +extern char **__libc_argv attribute_hidden; +extern char **_dl_argv; + +#ifndef SHARED +unsigned short __init1_desc; +static tcbhead_t __init1_tcbhead; +#endif + +/* Things that want to be run before _hurd_init or much anything else. + Importantly, these are called before anything tries to use malloc. */ +DEFINE_HOOK (_hurd_preinit_hook, (void)); + + +/* We call this once the Hurd magic is all set up and we are ready to be a + Posixoid program. This does the same things the generic version does. */ +static void +posixland_init (int argc, char **argv, char **envp) +{ + /* Now we have relocations etc. we can start signals etc. */ + _hurd_libc_proc_init (argv); + +#ifdef SHARED + /* Make sure we don't initialize twice. */ + if (__libc_initial) + { + /* Set the FPU control word to the proper default value. */ + __setfpucw (__fpu_control); + } + else + { + /* Initialize data structures so the additional libc can do RPCs. */ + __mach_init (); + } +#else /* !SHARED */ + __setfpucw (__fpu_control); +#endif + + /* Save the command-line arguments. */ + __libc_argc = argc; + __libc_argv = argv; + __environ = envp; + +#ifndef SHARED + _dl_non_dynamic_init (); +#endif + __init_misc (argc, argv, envp); +} + +static void +init (void **data) +{ + int argc = (int) *data; + char **argv = (void *) (data + 1); + char **envp = &argv[argc + 1]; + struct hurd_startup_data *d; + + /* Since the cthreads initialization code uses malloc, and the + malloc initialization code needs to get at the environment, make + sure we can find it. We'll need to do this again later on since + switching stacks changes the location where the environment is + stored. */ + __environ = envp; + + while (*envp) + ++envp; + d = (void *) ++envp; + +#ifndef SHARED + + /* If we are the bootstrap task started by the kernel, + then after the environment pointers there is no Hurd + data block; the argument strings start there. */ + if ((void *) d == argv[0] || d->phdr == 0) + { + __libc_enable_secure = 0; + /* With a new enough linker (binutils-2.23 or better), + the magic __ehdr_start symbol will be available and + __libc_start_main will have done this that way already. */ + if (_dl_phdr == NULL) + { + /* We may need to see our own phdrs, e.g. for TLS setup. + Try the usual kludge to find the headers without help from + the exec server. */ + extern const void __executable_start; + const ElfW(Ehdr) *const ehdr = &__executable_start; + _dl_phdr = (const void *) ehdr + ehdr->e_phoff; + _dl_phnum = ehdr->e_phnum; + assert (ehdr->e_phentsize == sizeof (ElfW(Phdr))); + } + } + else + { + __libc_enable_secure = d->flags & EXEC_SECURE; + _dl_phdr = (ElfW(Phdr) *) d->phdr; + _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr)); + assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0); + } +#endif + + if ((void *) d == argv[0]) + return; + + _hurd_init_dtable = d->dtable; + _hurd_init_dtablesize = d->dtablesize; + + if (d->portarray || d->intarray) + /* Initialize library data structures, start signal processing, etc. */ + _hurd_init (d->flags, argv, + d->portarray, d->portarraysize, + d->intarray, d->intarraysize); +} + +/* Do the first essential initializations that must precede all else. */ +static inline void +first_init (void) +{ + /* Initialize data structures so we can do RPCs. */ + __mach_init (); + +#ifndef SHARED + /* In the static case, we need to set up TLS early so that the stack + protection guard can be read at gs:0x14 by the gcc-generated snippets. */ + _hurd_tls_init (&__init1_tcbhead); + asm ("movw %%gs,%w0" : "=m" (__init1_desc)); +#endif + + RUN_RELHOOK (_hurd_preinit_hook, ()); +} + +#ifdef SHARED +/* This function is called specially by the dynamic linker to do early + initialization of the shared C library before normal initializers + expecting a Posixoid environment can run. */ + +void +_dl_init_first (void *data) +{ + first_init (); + init (data); +} + +/* The regular posixland initialization is what goes into libc's + normal initializer. */ +/* NOTE! The linker notices the magical name `_init' and sets the DT_INIT + pointer in the dynamic section based solely on that. It is convention + for this function to be in the `.init' section, but the symbol name is + the only thing that really matters!! */ +strong_alias (posixland_init, _init); + +void +__libc_init_first (int argc, char **argv, char **envp) +{ + /* Everything was done in the shared library initializer, _init. */ +} + +#else /* SHARED */ + +strong_alias (posixland_init, __libc_init_first); + +/* XXX This is all a crock and I am not happy with it. + This poorly-named function is called by static-start.S, + which should not exist at all. */ +void +inhibit_stack_protector +_hurd_stack_setup (void) +{ + /* This is the very first C code that runs in a statically linked + executable -- calling this function is the first thing that _start in + static-start.S does. Once this function returns, the unusual way that it + does (see below), _start jumps to _start1, the regular start-up code. + + _start1 expects the arguments, environment, and a Hurd data block to be + located at the top of the stack. The data may already be located there, + or we may need to receive it from the exec server. */ + void *caller = __builtin_extract_return_addr (__builtin_return_address (0)); + /* If the arguments and environment are already located on the stack, this is + where they are, just above our call frame. Note that this may not be a + valid pointer in case we're supposed to receive the arguments from the exec + server, so we can not dereference it yet. */ + void **p = (void **) __builtin_frame_address (0) + 2; + + /* Init the essential things. */ + first_init (); + + void doinit (intptr_t *data) + { + init ((void **) data); +# ifdef __x86_64__ + asm volatile ("movq %0, %%rsp\n" /* Switch to new outermost stack. */ + "xorq %%rbp, %%rbp\n" /* Clear outermost frame pointer. */ + "jmp *%1" : : "r" (data), "r" (caller)); +# else + asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack. */ + "xorl %%ebp, %%ebp\n" /* Clear outermost frame pointer. */ + "jmp *%1" : : "r" (data), "r" (caller)); +# endif + __builtin_unreachable (); + } + + /* _hurd_startup () will attempt to receive the data block from the exec + server; or if that is not possible, will take the data from the pointer + we pass it here. The important point here is that the data + _hurd_startup () collects may be allocated in its stack frame (with + alloca), which is why _hurd_startup () does not return the normal way. + Instead, it invokes a callback (which is not expected to return normally + either). + + Our callback not only passes the data pointer to init (), but also jumps + out of the call stack back to our caller (i.e. to _start1), while setting + the stack pointer to the data (which is somewhere on the current stack + anyway). This way, _start1 find the data on the top of the stack, just as + it expects to. */ + _hurd_startup (p, &doinit); + __builtin_unreachable (); +} +#endif + + +/* This function is defined here so that if this file ever gets into + ld.so we will get a link error. Having this file silently included + in ld.so causes disaster, because the _init definition above will + cause ld.so to gain an init function, which is not a cool thing. */ + +void +_dl_start (void) +{ + abort (); +} -- cgit 1.4.1