(root)/
glibc-2.38/
sysdeps/
mach/
hurd/
x86/
init-first.c
       1  /* Initialization code run first thing by the ELF startup code.  For x86/Hurd.
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <hurd.h>
      21  #include <stdio.h>
      22  #include <unistd.h>
      23  #include <string.h>
      24  #include <sysdep.h>
      25  #include <dl-sysdep.h>
      26  #include <set-hooks.h>
      27  #include "hurdstartup.h"
      28  
      29  #include <ldsodefs.h>
      30  #include <fpu_control.h>
      31  #include <libc-diag.h>
      32  #include <libc-internal.h>
      33  
      34  extern void __mach_init (void);
      35  extern void __init_misc (int, char **, char **);
      36  
      37  extern int __libc_argc attribute_hidden;
      38  extern char **__libc_argv attribute_hidden;
      39  extern char **_dl_argv;
      40  
      41  #ifndef SHARED
      42  static tcbhead_t __init1_tcbhead;
      43  #endif
      44  
      45  /* Things that want to be run before _hurd_init or much anything else.
      46     Importantly, these are called before anything tries to use malloc.  */
      47  DEFINE_HOOK (_hurd_preinit_hook, (void));
      48  
      49  
      50  /* We call this once the Hurd magic is all set up and we are ready to be a
      51     Posixoid program.  This does the same things the generic version does.  */
      52  static void
      53  posixland_init (int argc, char **argv, char **envp)
      54  {
      55    /* Now we have relocations etc. we can start signals etc.  */
      56    _hurd_libc_proc_init (argv);
      57  
      58  #ifdef SHARED
      59    /* Make sure we don't initialize twice.  */
      60    if (__libc_initial)
      61      {
      62        /* Set the FPU control word to the proper default value.  */
      63        __setfpucw (__fpu_control);
      64      }
      65    else
      66      {
      67        /* Initialize data structures so the additional libc can do RPCs.  */
      68        __mach_init ();
      69      }
      70  #else /* !SHARED */
      71    __setfpucw (__fpu_control);
      72  #endif
      73  
      74    /* Save the command-line arguments.  */
      75    __libc_argc = argc;
      76    __libc_argv = argv;
      77    __environ = envp;
      78  
      79  #ifndef SHARED
      80    _dl_non_dynamic_init ();
      81  #endif
      82    __init_misc (argc, argv, envp);
      83  }
      84  
      85  static void
      86  init (void **data)
      87  {
      88    int argc = (int) (uintptr_t) *data;
      89    char **argv = (void *) (data + 1);
      90    char **envp = &argv[argc + 1];
      91    struct hurd_startup_data *d;
      92  
      93    /* Since the cthreads initialization code uses malloc, and the
      94       malloc initialization code needs to get at the environment, make
      95       sure we can find it.  We'll need to do this again later on since
      96       switching stacks changes the location where the environment is
      97       stored.  */
      98    __environ = envp;
      99  
     100    while (*envp)
     101      ++envp;
     102    d = (void *) ++envp;
     103  
     104  #ifndef SHARED
     105  
     106    /* If we are the bootstrap task started by the kernel,
     107       then after the environment pointers there is no Hurd
     108       data block; the argument strings start there.  */
     109    if ((void *) d == argv[0] || d->phdr == 0)
     110      {
     111        __libc_enable_secure = 0;
     112        /* With a new enough linker (binutils-2.23 or better),
     113           the magic __ehdr_start symbol will be available and
     114           __libc_start_main will have done this that way already.  */
     115        if (_dl_phdr == NULL)
     116          {
     117            /* We may need to see our own phdrs, e.g. for TLS setup.
     118               Try the usual kludge to find the headers without help from
     119               the exec server.  */
     120            extern const void __executable_start;
     121            const ElfW(Ehdr) *const ehdr = &__executable_start;
     122            _dl_phdr = (const void *) ehdr + ehdr->e_phoff;
     123            _dl_phnum = ehdr->e_phnum;
     124            assert (ehdr->e_phentsize == sizeof (ElfW(Phdr)));
     125          }
     126      }
     127    else
     128      {
     129        __libc_enable_secure = d->flags & EXEC_SECURE;
     130        _dl_phdr = (ElfW(Phdr) *) d->phdr;
     131        _dl_phnum = d->phdrsz / sizeof (ElfW(Phdr));
     132        assert (d->phdrsz % sizeof (ElfW(Phdr)) == 0);
     133      }
     134  #endif
     135  
     136    if ((void *) d == argv[0])
     137      return;
     138  
     139    _hurd_init_dtable = d->dtable;
     140    _hurd_init_dtablesize = d->dtablesize;
     141  
     142    if (d->portarray || d->intarray)
     143      /* Initialize library data structures, start signal processing, etc.  */
     144      _hurd_init (d->flags, argv,
     145  		d->portarray, d->portarraysize,
     146  		d->intarray, d->intarraysize);
     147  }
     148  
     149  /* Do the first essential initializations that must precede all else.  */
     150  static inline void
     151  first_init (void)
     152  {
     153    /* Initialize data structures so we can do RPCs.  */
     154    __mach_init ();
     155  
     156  #ifndef SHARED
     157    /* In the static case, we need to set up TLS early so that the stack
     158       protection guard can be read at gs:0x14 by the gcc-generated snippets.  */
     159    _hurd_tls_init (&__init1_tcbhead, 0);
     160  #endif
     161  
     162    RUN_RELHOOK (_hurd_preinit_hook, ());
     163  }
     164  
     165  #ifdef SHARED
     166  /* This function is called specially by the dynamic linker to do early
     167     initialization of the shared C library before normal initializers
     168     expecting a Posixoid environment can run.  */
     169  
     170  void
     171  _dl_init_first (void *data)
     172  {
     173    first_init ();
     174    init (data);
     175  }
     176  
     177  /* The regular posixland initialization is what goes into libc's
     178     normal initializer.  */
     179  /* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
     180     pointer in the dynamic section based solely on that.  It is convention
     181     for this function to be in the `.init' section, but the symbol name is
     182     the only thing that really matters!!  */
     183  strong_alias (posixland_init, _init);
     184  
     185  void
     186  __libc_init_first (int argc, char **argv, char **envp)
     187  {
     188    /* Everything was done in the shared library initializer, _init.  */
     189  }
     190  
     191  #else /* SHARED */
     192  
     193  strong_alias (posixland_init, __libc_init_first);
     194  
     195  /* XXX This is all a crock and I am not happy with it.
     196     This poorly-named function is called by static-start.S,
     197     which should not exist at all.  */
     198  void
     199  inhibit_stack_protector
     200  _hurd_stack_setup (void)
     201  {
     202    /* This is the very first C code that runs in a statically linked
     203       executable -- calling this function is the first thing that _start in
     204       static-start.S does.  Once this function returns, the unusual way that it
     205       does (see below), _start jumps to _start1, the regular start-up code.
     206  
     207       _start1 expects the arguments, environment, and a Hurd data block to be
     208       located at the top of the stack.  The data may already be located there,
     209       or we may need to receive it from the exec server.  */
     210    void *caller = __builtin_extract_return_addr (__builtin_return_address (0));
     211    /* If the arguments and environment are already located on the stack, this is
     212       where they are, just above our call frame.  Note that this may not be a
     213       valid pointer in case we're supposed to receive the arguments from the exec
     214       server, so we can not dereference it yet.  */
     215    void **p = (void **) __builtin_frame_address (0) + 2;
     216  
     217    /* Init the essential things.  */
     218    first_init ();
     219  
     220    void doinit (intptr_t *data)
     221      {
     222        init ((void **) data);
     223  # ifdef __x86_64__
     224        asm volatile ("movq %0, %%rsp\n" /* Switch to new outermost stack.  */
     225                      "xorq %%rbp, %%rbp\n" /* Clear outermost frame pointer.  */
     226                      "jmp *%1" : : "r" (data), "r" (caller));
     227  # else
     228        asm volatile ("movl %0, %%esp\n" /* Switch to new outermost stack.  */
     229  		    "xorl %%ebp, %%ebp\n" /* Clear outermost frame pointer.  */
     230  		    "jmp *%1" : : "r" (data), "r" (caller));
     231  # endif
     232        __builtin_unreachable ();
     233      }
     234  
     235    /* _hurd_startup () will attempt to receive the data block from the exec
     236       server; or if that is not possible, will take the data from the pointer
     237       we pass it here.  The important point here is that the data
     238       _hurd_startup () collects may be allocated in its stack frame (with
     239       alloca), which is why _hurd_startup () does not return the normal way.
     240       Instead, it invokes a callback (which is not expected to return normally
     241       either).
     242  
     243       Our callback not only passes the data pointer to init (), but also jumps
     244       out of the call stack back to our caller (i.e. to _start1), while setting
     245       the stack pointer to the data (which is somewhere on the current stack
     246       anyway).  This way, _start1 find the data on the top of the stack, just as
     247       it expects to.  */
     248    _hurd_startup (p, &doinit);
     249    __builtin_unreachable ();
     250  }
     251  #endif
     252  
     253  
     254  /* This function is defined here so that if this file ever gets into
     255     ld.so we will get a link error.  Having this file silently included
     256     in ld.so causes disaster, because the _init definition above will
     257     cause ld.so to gain an init function, which is not a cool thing. */
     258  
     259  void
     260  _dl_start (void)
     261  {
     262    abort ();
     263  }