Blame csu/libc-start.c

Packit 6c4009
/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <exit-thread.h>
Packit 6c4009
#include <libc-internal.h>
Packit 6c4009
Packit 6c4009
#include <elf/dl-tunables.h>
Packit 6c4009
Packit 6c4009
extern void __libc_init_first (int argc, char **argv, char **envp);
Packit 6c4009
Packit 6c4009
#include <tls.h>
Packit 6c4009
#ifndef SHARED
Packit 6c4009
# include <dl-osinfo.h>
Packit 6c4009
# ifndef THREAD_SET_STACK_GUARD
Packit 6c4009
/* Only exported for architectures that don't store the stack guard canary
Packit 6c4009
   in thread local area.  */
Packit 6c4009
uintptr_t __stack_chk_guard attribute_relro;
Packit 6c4009
# endif
Packit 6c4009
# ifndef  THREAD_SET_POINTER_GUARD
Packit 6c4009
/* Only exported for architectures that don't store the pointer guard
Packit 6c4009
   value in thread local area.  */
Packit 6c4009
uintptr_t __pointer_chk_guard_local
Packit 6c4009
	attribute_relro attribute_hidden __attribute__ ((nocommon));
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef HAVE_PTR_NTHREADS
Packit 6c4009
/* We need atomic operations.  */
Packit 6c4009
# include <atomic.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifndef SHARED
Packit 6c4009
# include <link.h>
Packit 6c4009
# include <dl-irel.h>
Packit 6c4009
Packit 6c4009
# ifdef ELF_MACHINE_IRELA
Packit 6c4009
#  define IREL_T	ElfW(Rela)
Packit 6c4009
#  define IPLT_START	__rela_iplt_start
Packit 6c4009
#  define IPLT_END	__rela_iplt_end
Packit 6c4009
#  define IREL		elf_irela
Packit 6c4009
# elif defined ELF_MACHINE_IREL
Packit 6c4009
#  define IREL_T	ElfW(Rel)
Packit 6c4009
#  define IPLT_START	__rel_iplt_start
Packit 6c4009
#  define IPLT_END	__rel_iplt_end
Packit 6c4009
#  define IREL		elf_irel
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
apply_irel (void)
Packit 6c4009
{
Packit 6c4009
# ifdef IREL
Packit 6c4009
  /* We use weak references for these so that we'll still work with a linker
Packit 6c4009
     that doesn't define them.  Such a linker doesn't support IFUNC at all
Packit 6c4009
     and so uses won't work, but a statically-linked program that doesn't
Packit 6c4009
     use any IFUNC symbols won't have a problem.  */
Packit 6c4009
  extern const IREL_T IPLT_START[] __attribute__ ((weak));
Packit 6c4009
  extern const IREL_T IPLT_END[] __attribute__ ((weak));
Packit 6c4009
  for (const IREL_T *ipltent = IPLT_START; ipltent < IPLT_END; ++ipltent)
Packit 6c4009
    IREL (ipltent);
Packit 6c4009
# endif
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef LIBC_START_MAIN
Packit 6c4009
# ifdef LIBC_START_DISABLE_INLINE
Packit 6c4009
#  define STATIC static
Packit 6c4009
# else
Packit 6c4009
#  define STATIC static inline __attribute__ ((always_inline))
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
# define STATIC
Packit 6c4009
# define LIBC_START_MAIN __libc_start_main
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef MAIN_AUXVEC_ARG
Packit 6c4009
/* main gets passed a pointer to the auxiliary.  */
Packit 6c4009
# define MAIN_AUXVEC_DECL	, void *
Packit 6c4009
# define MAIN_AUXVEC_PARAM	, auxvec
Packit 6c4009
#else
Packit 6c4009
# define MAIN_AUXVEC_DECL
Packit 6c4009
# define MAIN_AUXVEC_PARAM
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef ARCH_INIT_CPU_FEATURES
Packit 6c4009
# define ARCH_INIT_CPU_FEATURES()
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <libc-start.h>
Packit 6c4009
Packit 6c4009
STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
Packit 6c4009
					 MAIN_AUXVEC_DECL),
Packit 6c4009
			    int argc,
Packit 6c4009
			    char **argv,
Packit 6c4009
#ifdef LIBC_START_MAIN_AUXVEC_ARG
Packit 6c4009
			    ElfW(auxv_t) *auxvec,
Packit 6c4009
#endif
Packit 6c4009
			    __typeof (main) init,
Packit 6c4009
			    void (*fini) (void),
Packit 6c4009
			    void (*rtld_fini) (void),
Packit 6c4009
			    void *stack_end)
Packit 6c4009
     __attribute__ ((noreturn));
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Note: the fini parameter is ignored here for shared library.  It
Packit 6c4009
   is registered with __cxa_atexit.  This had the disadvantage that
Packit 6c4009
   finalizers were called in more than one place.  */
Packit 6c4009
STATIC int
Packit 6c4009
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
Packit 6c4009
		 int argc, char **argv,
Packit 6c4009
#ifdef LIBC_START_MAIN_AUXVEC_ARG
Packit 6c4009
		 ElfW(auxv_t) *auxvec,
Packit 6c4009
#endif
Packit 6c4009
		 __typeof (main) init,
Packit 6c4009
		 void (*fini) (void),
Packit 6c4009
		 void (*rtld_fini) (void), void *stack_end)
Packit 6c4009
{
Packit 6c4009
  /* Result of the 'main' function.  */
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
Packit 6c4009
Packit 6c4009
#ifndef SHARED
Packit 6c4009
  _dl_relocate_static_pie ();
Packit 6c4009
Packit 6c4009
  char **ev = &argv[argc + 1];
Packit 6c4009
Packit 6c4009
  __environ = ev;
Packit 6c4009
Packit 6c4009
  /* Store the lowest stack address.  This is done in ld.so if this is
Packit 6c4009
     the code for the DSO.  */
Packit 6c4009
  __libc_stack_end = stack_end;
Packit 6c4009
Packit 6c4009
# ifdef HAVE_AUX_VECTOR
Packit 6c4009
  /* First process the auxiliary vector since we need to find the
Packit 6c4009
     program header to locate an eventually present PT_TLS entry.  */
Packit 6c4009
#  ifndef LIBC_START_MAIN_AUXVEC_ARG
Packit 6c4009
  ElfW(auxv_t) *auxvec;
Packit 6c4009
  {
Packit 6c4009
    char **evp = ev;
Packit 6c4009
    while (*evp++ != NULL)
Packit 6c4009
      ;
Packit 6c4009
    auxvec = (ElfW(auxv_t) *) evp;
Packit 6c4009
  }
Packit 6c4009
#  endif
Packit 6c4009
  _dl_aux_init (auxvec);
Packit 6c4009
  if (GL(dl_phdr) == NULL)
Packit 6c4009
# endif
Packit 6c4009
    {
Packit 6c4009
      /* Starting from binutils-2.23, the linker will define the
Packit 6c4009
         magic symbol __ehdr_start to point to our own ELF header
Packit 6c4009
         if it is visible in a segment that also includes the phdrs.
Packit 6c4009
         So we can set up _dl_phdr and _dl_phnum even without any
Packit 6c4009
         information from auxv.  */
Packit 6c4009
Packit 6c4009
      extern const ElfW(Ehdr) __ehdr_start
Packit 6c4009
	__attribute__ ((weak, visibility ("hidden")));
Packit 6c4009
      if (&__ehdr_start != NULL)
Packit 6c4009
        {
Packit 6c4009
          assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr));
Packit 6c4009
          GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
Packit 6c4009
          GL(dl_phnum) = __ehdr_start.e_phnum;
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Initialize very early so that tunables can use it.  */
Packit 6c4009
  __libc_init_secure ();
Packit 6c4009
Packit 6c4009
  __tunables_init (__environ);
Packit 6c4009
Packit 6c4009
  ARCH_INIT_CPU_FEATURES ();
Packit 6c4009
Packit 6c4009
  /* Perform IREL{,A} relocations.  */
Packit 6c4009
  ARCH_SETUP_IREL ();
Packit 6c4009
Packit 6c4009
  /* The stack guard goes into the TCB, so initialize it early.  */
Packit 6c4009
  ARCH_SETUP_TLS ();
Packit 6c4009
Packit 6c4009
  /* In some architectures, IREL{,A} relocations happen after TLS setup in
Packit 6c4009
     order to let IFUNC resolvers benefit from TCB information, e.g. powerpc's
Packit 6c4009
     hwcap and platform fields available in the TCB.  */
Packit 6c4009
  ARCH_APPLY_IREL ();
Packit 6c4009
Packit 6c4009
  /* Set up the stack checker's canary.  */
Packit 6c4009
  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
Packit 6c4009
# ifdef THREAD_SET_STACK_GUARD
Packit 6c4009
  THREAD_SET_STACK_GUARD (stack_chk_guard);
Packit 6c4009
# else
Packit 6c4009
  __stack_chk_guard = stack_chk_guard;
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
# ifdef DL_SYSDEP_OSCHECK
Packit 6c4009
  if (!__libc_multiple_libcs)
Packit 6c4009
    {
Packit 6c4009
      /* This needs to run to initiliaze _dl_osversion before TLS
Packit 6c4009
	 setup might check it.  */
Packit 6c4009
      DL_SYSDEP_OSCHECK (__libc_fatal);
Packit 6c4009
    }
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  /* Initialize libpthread if linked in.  */
Packit 6c4009
  if (__pthread_initialize_minimal != NULL)
Packit 6c4009
    __pthread_initialize_minimal ();
Packit 6c4009
Packit 6c4009
  /* Set up the pointer guard value.  */
Packit 6c4009
  uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
Packit 6c4009
							 stack_chk_guard);
Packit 6c4009
# ifdef THREAD_SET_POINTER_GUARD
Packit 6c4009
  THREAD_SET_POINTER_GUARD (pointer_chk_guard);
Packit 6c4009
# else
Packit 6c4009
  __pointer_chk_guard_local = pointer_chk_guard;
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
#endif /* !SHARED  */
Packit 6c4009
Packit 6c4009
  /* Register the destructor of the dynamic linker if there is any.  */
Packit 6c4009
  if (__glibc_likely (rtld_fini != NULL))
Packit 6c4009
    __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
Packit 6c4009
Packit 6c4009
#ifndef SHARED
Packit 6c4009
  /* Call the initializer of the libc.  This is only needed here if we
Packit 6c4009
     are compiling for the static library in which case we haven't
Packit 6c4009
     run the constructors in `_dl_start_user'.  */
Packit 6c4009
  __libc_init_first (argc, argv, __environ);
Packit 6c4009
Packit 6c4009
  /* Register the destructor of the program, if any.  */
Packit 6c4009
  if (fini)
Packit 6c4009
    __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
Packit 6c4009
Packit 6c4009
  /* Some security at this point.  Prevent starting a SUID binary where
Packit 6c4009
     the standard file descriptors are not opened.  We have to do this
Packit 6c4009
     only for statically linked applications since otherwise the dynamic
Packit 6c4009
     loader did the work already.  */
Packit 6c4009
  if (__builtin_expect (__libc_enable_secure, 0))
Packit 6c4009
    __libc_check_standard_fds ();
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Call the initializer of the program, if any.  */
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
Packit 6c4009
    GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
Packit 6c4009
#endif
Packit 6c4009
  if (init)
Packit 6c4009
    (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Auditing checkpoint: we have a new object.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_naudit) > 0))
Packit 6c4009
    {
Packit 6c4009
      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
      struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit 6c4009
      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (afct->preinit != NULL)
Packit Service 541783
	    afct->preinit (&head->l_audit[cnt].cookie);
Packit 6c4009
Packit 6c4009
	  afct = afct->next;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
Packit 6c4009
    GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef SHARED
Packit 6c4009
  _dl_debug_initialize (0, LM_ID_BASE);
Packit 6c4009
#endif
Packit 6c4009
#ifdef HAVE_CLEANUP_JMP_BUF
Packit 6c4009
  /* Memory for the cancellation buffer.  */
Packit 6c4009
  struct pthread_unwind_buf unwind_buf;
Packit 6c4009
Packit 6c4009
  int not_first_call;
Packit 6c4009
  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
Packit 6c4009
  if (__glibc_likely (! not_first_call))
Packit 6c4009
    {
Packit 6c4009
      struct pthread *self = THREAD_SELF;
Packit 6c4009
Packit 6c4009
      /* Store old info.  */
Packit 6c4009
      unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
Packit 6c4009
      unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
Packit 6c4009
Packit 6c4009
      /* Store the new cleanup handler info.  */
Packit 6c4009
      THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
Packit 6c4009
Packit 6c4009
      /* Run the program.  */
Packit 6c4009
      result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Remove the thread-local data.  */
Packit 6c4009
# ifdef SHARED
Packit 6c4009
      PTHFCT_CALL (ptr__nptl_deallocate_tsd, ());
Packit 6c4009
# else
Packit 6c4009
      extern void __nptl_deallocate_tsd (void) __attribute ((weak));
Packit 6c4009
      __nptl_deallocate_tsd ();
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
      /* One less thread.  Decrement the counter.  If it is zero we
Packit 6c4009
	 terminate the entire process.  */
Packit 6c4009
      result = 0;
Packit 6c4009
# ifdef SHARED
Packit 6c4009
      unsigned int *ptr = __libc_pthread_functions.ptr_nthreads;
Packit 6c4009
#  ifdef PTR_DEMANGLE
Packit 6c4009
      PTR_DEMANGLE (ptr);
Packit 6c4009
#  endif
Packit 6c4009
# else
Packit 6c4009
      extern unsigned int __nptl_nthreads __attribute ((weak));
Packit 6c4009
      unsigned int *const ptr = &__nptl_nthreads;
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
      if (! atomic_decrement_and_test (ptr))
Packit 6c4009
	/* Not much left to do but to exit the thread, not the process.  */
Packit 6c4009
	__exit_thread ();
Packit 6c4009
    }
Packit 6c4009
#else
Packit 6c4009
  /* Nothing fancy, just call the function.  */
Packit 6c4009
  result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  exit (result);
Packit 6c4009
}