summary refs log tree commit diff
path: root/csu
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2005-12-14 15:06:39 +0000
committerUlrich Drepper <drepper@redhat.com>2005-12-14 15:06:39 +0000
commit9d13fb2413921c713f83efe331e8e4d219c62c6b (patch)
tree2d44d7ac45ab2d147eb8361bbff880c365aa8ad5 /csu
parentb6ab06cef4670e02756bcdd4d2c33a49369a4346 (diff)
downloadglibc-9d13fb2413921c713f83efe331e8e4d219c62c6b.tar.gz
glibc-9d13fb2413921c713f83efe331e8e4d219c62c6b.tar.xz
glibc-9d13fb2413921c713f83efe331e8e4d219c62c6b.zip
Moved to csu/errno-loc.c.
Diffstat (limited to 'csu')
-rw-r--r--csu/errno.c53
-rw-r--r--csu/init-first.c59
-rw-r--r--csu/libc-start.c263
-rw-r--r--csu/libc-tls.c263
-rw-r--r--csu/start.c13
-rw-r--r--csu/sysdep.c2
6 files changed, 653 insertions, 0 deletions
diff --git a/csu/errno.c b/csu/errno.c
new file mode 100644
index 0000000000..03d661b717
--- /dev/null
+++ b/csu/errno.c
@@ -0,0 +1,53 @@
+/* Definition of `errno' variable.  Canonical version.
+   Copyright (C) 2002, 2004 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <tls.h>
+#include <dl-sysdep.h>
+#undef errno
+
+#if RTLD_PRIVATE_ERRNO
+
+/* Code compiled for rtld refers only to this name.  */
+int rtld_errno attribute_hidden;
+
+#elif USE___THREAD
+
+__thread int errno;
+extern __thread int __libc_errno __attribute__ ((alias ("errno")))
+  attribute_hidden;
+
+#else
+
+/* This differs from plain `int errno;' in that it doesn't create
+   a common definition, but a plain symbol that resides in .bss,
+   which can have an alias.  */
+int errno __attribute__ ((nocommon));
+strong_alias (errno, _errno)
+
+/* We declare these with compat_symbol so that they are not visible at
+   link time.  Programs must use the accessor functions.  RTLD is special,
+   since it's not exported from there at any time.  */
+# if defined HAVE_ELF && defined SHARED && defined DO_VERSIONING
+#  include <shlib-compat.h>
+compat_symbol (libc, errno, errno, GLIBC_2_0);
+compat_symbol (libc, _errno, _errno, GLIBC_2_0);
+# endif
+
+#endif
diff --git a/csu/init-first.c b/csu/init-first.c
new file mode 100644
index 0000000000..fa21274c73
--- /dev/null
+++ b/csu/init-first.c
@@ -0,0 +1,59 @@
+/* Initialization code run first thing by the ELF startup code.  Stub version.
+   Copyright (C) 1995, 1997, 1998, 2001, 2002 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+/* Set nonzero if we have to be prepared for more then one libc being
+   used in the process.  Safe assumption if initializer never runs.  */
+int __libc_multiple_libcs attribute_hidden = 1;
+
+extern void __libc_init (int, char **, char **);
+#ifdef USE_NONOPTION_FLAGS
+extern void __getopt_clean_environment (char **);
+#endif
+
+#ifdef SHARED
+void
+__libc_init_first (void)
+{
+}
+#endif
+
+#ifdef SHARED
+/* 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!!  */
+void _init
+#else
+void __libc_init_first
+#endif
+(int argc, char *arg0, ...)
+{
+  char **argv = &arg0, **envp = &argv[argc + 1];
+
+  __environ = envp;
+  __libc_init (argc, argv, envp);
+
+#ifdef USE_NONOPTION_FLAGS
+  /* This is a hack to make the special getopt in GNU libc working.  */
+  __getopt_clean_environment (envp);
+#endif
+}
diff --git a/csu/libc-start.c b/csu/libc-start.c
new file mode 100644
index 0000000000..194db6b1ec
--- /dev/null
+++ b/csu/libc-start.c
@@ -0,0 +1,263 @@
+/* Copyright (C) 1998-2003, 2004, 2005 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <bp-start.h>
+#include <bp-sym.h>
+
+extern void __libc_init_first (int argc, char **argv, char **envp);
+
+extern int __libc_multiple_libcs;
+
+#include <tls.h>
+#ifndef SHARED
+# include <dl-osinfo.h>
+extern void __pthread_initialize_minimal (void)
+# if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
+     __attribute__ ((weak))
+# endif
+     ;
+# ifndef THREAD_SET_STACK_GUARD
+/* Only exported for architectures that don't store the stack guard canary
+   in thread local area.  */
+uintptr_t __stack_chk_guard attribute_relro;
+# endif
+#endif
+
+#ifdef HAVE_PTR_NTHREADS
+/* We need atomic operations.  */
+# include <atomic.h>
+#endif
+
+
+#ifdef LIBC_START_MAIN
+# ifdef LIBC_START_DISABLE_INLINE
+#  define STATIC static
+# else
+#  define STATIC static inline __attribute__ ((always_inline))
+# endif
+#else
+# define STATIC
+# define LIBC_START_MAIN BP_SYM (__libc_start_main)
+#endif
+
+#ifdef MAIN_AUXVEC_ARG
+/* main gets passed a pointer to the auxiliary.  */
+# define MAIN_AUXVEC_DECL	, void *
+# define MAIN_AUXVEC_PARAM	, auxvec
+#else
+# define MAIN_AUXVEC_DECL
+# define MAIN_AUXVEC_PARAM
+#endif
+
+STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
+					 MAIN_AUXVEC_DECL),
+			    int argc,
+			    char *__unbounded *__unbounded ubp_av,
+#ifdef LIBC_START_MAIN_AUXVEC_ARG
+			    ElfW(auxv_t) *__unbounded auxvec,
+#endif
+			    __typeof (main) init,
+			    void (*fini) (void),
+			    void (*rtld_fini) (void),
+			    void *__unbounded stack_end)
+     __attribute__ ((noreturn));
+
+
+/* Note: the fini parameter is ignored here for shared library.  It
+   is registered with __cxa_atexit.  This had the disadvantage that
+   finalizers were called in more than one place.  */
+STATIC int
+LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
+		 int argc, char *__unbounded *__unbounded ubp_av,
+#ifdef LIBC_START_MAIN_AUXVEC_ARG
+		 ElfW(auxv_t) *__unbounded auxvec,
+#endif
+		 __typeof (main) init,
+		 void (*fini) (void),
+		 void (*rtld_fini) (void), void *__unbounded stack_end)
+{
+#if __BOUNDED_POINTERS__
+  char **argv;
+#else
+# define argv ubp_av
+#endif
+
+  /* Result of the 'main' function.  */
+  int result;
+
+  __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
+
+#ifndef SHARED
+  char *__unbounded *__unbounded ubp_ev = &ubp_av[argc + 1];
+
+  INIT_ARGV_and_ENVIRON;
+
+  /* Store the lowest stack address.  This is done in ld.so if this is
+     the code for the DSO.  */
+  __libc_stack_end = stack_end;
+
+# ifdef HAVE_AUX_VECTOR
+  /* First process the auxiliary vector since we need to find the
+     program header to locate an eventually present PT_TLS entry.  */
+#  ifndef LIBC_START_MAIN_AUXVEC_ARG
+  ElfW(auxv_t) *__unbounded auxvec;
+  {
+    char *__unbounded *__unbounded evp = ubp_ev;
+    while (*evp++ != NULL)
+      ;
+    auxvec = (ElfW(auxv_t) *__unbounded) evp;
+  }
+#  endif
+  _dl_aux_init (auxvec);
+# endif
+# ifdef DL_SYSDEP_OSCHECK
+  if (!__libc_multiple_libcs)
+    {
+      /* This needs to run to initiliaze _dl_osversion before TLS
+	 setup might check it.  */
+      DL_SYSDEP_OSCHECK (__libc_fatal);
+    }
+# endif
+
+  /* Initialize the thread library at least a bit since the libgcc
+     functions are using thread functions if these are available and
+     we need to setup errno.  If there is no thread library and we
+     handle TLS the function is defined in the libc to initialized the
+     TLS handling.  */
+# if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
+  if (__pthread_initialize_minimal)
+# endif
+    __pthread_initialize_minimal ();
+#endif
+
+# ifndef SHARED
+  /* Set up the stack checker's canary.  */
+  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard ();
+#  ifdef THREAD_SET_STACK_GUARD
+  THREAD_SET_STACK_GUARD (stack_chk_guard);
+#  else
+  __stack_chk_guard = stack_chk_guard;
+#  endif
+#endif
+
+  /* Register the destructor of the dynamic linker if there is any.  */
+  if (__builtin_expect (rtld_fini != NULL, 1))
+    __cxa_atexit ((void (*) (void *)) rtld_fini, NULL, NULL);
+
+#ifndef SHARED
+  /* Call the initializer of the libc.  This is only needed here if we
+     are compiling for the static library in which case we haven't
+     run the constructors in `_dl_start_user'.  */
+  __libc_init_first (argc, argv, __environ);
+
+  /* Register the destructor of the program, if any.  */
+  if (fini)
+    __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
+
+  /* Some security at this point.  Prevent starting a SUID binary where
+     the standard file descriptors are not opened.  We have to do this
+     only for statically linked applications since otherwise the dynamic
+     loader did the work already.  */
+  if (__builtin_expect (__libc_enable_secure, 0))
+    __libc_check_standard_fds ();
+#endif
+
+  /* Call the initializer of the program, if any.  */
+#ifdef SHARED
+  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
+    GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
+#endif
+  if (init)
+    (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
+
+#ifdef SHARED
+  /* Auditing checkpoint: we have a new object.  */
+  if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
+    {
+      struct audit_ifaces *afct = GLRO(dl_audit);
+      struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+	{
+	  if (afct->preinit != NULL)
+	    afct->preinit (&head->l_audit[cnt].cookie);
+
+	  afct = afct->next;
+	}
+    }
+#endif
+
+#ifdef SHARED
+  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
+    GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
+#endif
+
+#ifdef HAVE_CLEANUP_JMP_BUF
+  /* Memory for the cancellation buffer.  */
+  struct pthread_unwind_buf unwind_buf;
+
+  int not_first_call;
+  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  if (__builtin_expect (! not_first_call, 1))
+    {
+      struct pthread *self = THREAD_SELF;
+
+      /* Store old info.  */
+      unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+      unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+
+      /* Store the new cleanup handler info.  */
+      THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
+
+      /* Run the program.  */
+      result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
+    }
+  else
+    {
+      /* Remove the thread-local data.  */
+# ifdef SHARED
+      __libc_pthread_functions.ptr__nptl_deallocate_tsd ();
+# else
+      extern void __nptl_deallocate_tsd (void) __attribute ((weak));
+      __nptl_deallocate_tsd ();
+# endif
+
+      /* One less thread.  Decrement the counter.  If it is zero we
+	 terminate the entire process.  */
+      result = 0;
+# ifdef SHARED
+      unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads;
+# else
+      extern unsigned int __nptl_nthreads __attribute ((weak));
+      unsigned int *const ptr = &__nptl_nthreads;
+# endif
+
+      if (! atomic_decrement_and_test (ptr))
+	/* Not much left to do but to exit the thread, not the process.  */
+	__exit_thread (0);
+    }
+#else
+  /* Nothing fancy, just call the function.  */
+  result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
+#endif
+
+  exit (result);
+}
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
new file mode 100644
index 0000000000..3544e396da
--- /dev/null
+++ b/csu/libc-tls.c
@@ -0,0 +1,263 @@
+/* Initialization code for TLS in statically linked application.
+   Copyright (C) 2002, 2003, 2004, 2005 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <ldsodefs.h>
+#include <tls.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/param.h>
+
+
+#ifdef SHARED
+ #error makefile bug, this file is for static only
+#endif
+
+#ifdef USE_TLS
+extern ElfW(Phdr) *_dl_phdr;
+extern size_t _dl_phnum;
+
+
+static dtv_t static_dtv[2 + TLS_SLOTINFO_SURPLUS];
+
+
+static struct
+{
+  struct dtv_slotinfo_list si;
+  /* The dtv_slotinfo_list data structure does not include the actual
+     information since it is defined as an array of size zero.  We define
+     here the necessary entries.  Note that it is not important whether
+     there is padding or not since we will always access the information
+     through the 'si' element.  */
+  struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS];
+} static_slotinfo;
+
+/* Fake link map for the application.  */
+static struct link_map static_map;
+
+
+/* Highest dtv index currently needed.  */
+size_t _dl_tls_max_dtv_idx;
+/* Flag signalling whether there are gaps in the module ID allocation.  */
+bool _dl_tls_dtv_gaps;
+/* Information about the dtv slots.  */
+struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
+/* Number of modules in the static TLS block.  */
+size_t _dl_tls_static_nelem;
+/* Size of the static TLS block.  Giving this initialized value
+   preallocates some surplus bytes in the static TLS area.  */
+size_t _dl_tls_static_size = 2048;
+/* Size actually allocated in the static TLS block.  */
+size_t _dl_tls_static_used;
+/* Alignment requirement of the static TLS block.  */
+size_t _dl_tls_static_align;
+
+/* Generation counter for the dtv.  */
+size_t _dl_tls_generation;
+
+
+/* Additional definitions needed by TLS initialization.  */
+#ifdef TLS_INIT_HELPER
+TLS_INIT_HELPER
+#endif
+
+static inline void
+init_slotinfo (void)
+{
+  /* Create the slotinfo list.  */
+  static_slotinfo.si.len = (((char *) (&static_slotinfo + 1)
+			     - (char *) &static_slotinfo.si.slotinfo[0])
+			    / sizeof static_slotinfo.si.slotinfo[0]);
+  // static_slotinfo.si.next = NULL;	already zero
+
+  /* The slotinfo list.  Will be extended by the code doing dynamic
+     linking.  */
+  GL(dl_tls_max_dtv_idx) = 1;
+  GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si;
+}
+
+static inline void
+init_static_tls (size_t memsz, size_t align)
+{
+  /* That is the size of the TLS memory for this object.  The initialized
+     value of _dl_tls_static_size is provided by dl-open.c to request some
+     surplus that permits dynamic loading of modules with IE-model TLS.  */
+  GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
+				    TLS_TCB_ALIGN);
+  GL(dl_tls_static_used) = memsz;
+  /* The alignment requirement for the static TLS block.  */
+  GL(dl_tls_static_align) = align;
+  /* Number of elements in the static TLS block.  */
+  GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
+}
+
+void
+__libc_setup_tls (size_t tcbsize, size_t tcbalign)
+{
+  void *tlsblock;
+  size_t memsz = 0;
+  size_t filesz = 0;
+  void *initimage = NULL;
+  size_t align = 0;
+  size_t max_align = tcbalign;
+  size_t tcb_offset;
+  ElfW(Phdr) *phdr;
+
+  /* Look through the TLS segment if there is any.  */
+  if (_dl_phdr != NULL)
+    for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
+      if (phdr->p_type == PT_TLS)
+	{
+	  /* Remember the values we need.  */
+	  memsz = phdr->p_memsz;
+	  filesz = phdr->p_filesz;
+	  initimage = (void *) phdr->p_vaddr;
+	  align = phdr->p_align;
+	  if (phdr->p_align > max_align)
+	    max_align = phdr->p_align;
+	  break;
+	}
+
+  /* We have to set up the TCB block which also (possibly) contains
+     'errno'.  Therefore we avoid 'malloc' which might touch 'errno'.
+     Instead we use 'sbrk' which would only uses 'errno' if it fails.
+     In this case we are right away out of memory and the user gets
+     what she/he deserves.
+
+     The initialized value of _dl_tls_static_size is provided by dl-open.c
+     to request some surplus that permits dynamic loading of modules with
+     IE-model TLS.  */
+# if TLS_TCB_AT_TP
+  tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
+  tlsblock = __sbrk (tcb_offset + tcbsize + max_align);
+# elif TLS_DTV_AT_TP
+  tcb_offset = roundup (tcbsize, align ?: 1);
+  tlsblock = __sbrk (tcb_offset + memsz + max_align
+		     + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
+  tlsblock += TLS_PRE_TCB_SIZE;
+# else
+  /* In case a model with a different layout for the TCB and DTV
+     is defined add another #elif here and in the following #ifs.  */
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+  /* Align the TLS block.  */
+  tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
+		       & ~(max_align - 1));
+
+  /* Initialize the dtv.  [0] is the length, [1] the generation counter.  */
+  static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2;
+  // static_dtv[1].counter = 0;		would be needed if not already done
+
+  /* Initialize the TLS block.  */
+# if TLS_TCB_AT_TP
+  static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
+			       - roundup (memsz, align ?: 1));
+  static_map.l_tls_offset = roundup (memsz, align ?: 1);
+# elif TLS_DTV_AT_TP
+  static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
+  static_map.l_tls_offset = tcb_offset;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+  static_dtv[2].pointer.is_static = true;
+  /* sbrk gives us zero'd memory, so we don't need to clear the remainder.  */
+  memcpy (static_dtv[2].pointer.val, initimage, filesz);
+
+  /* Install the pointer to the dtv.  */
+
+  /* Initialize the thread pointer.  */
+# if TLS_TCB_AT_TP
+  INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv);
+
+  const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0);
+# elif TLS_DTV_AT_TP
+  INSTALL_DTV (tlsblock, static_dtv);
+  const char *lossage = TLS_INIT_TP (tlsblock, 0);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+  if (__builtin_expect (lossage != NULL, 0))
+    __libc_fatal (lossage);
+
+  /* We have to create a fake link map which normally would be created
+     by the dynamic linker.  It just has to have enough information to
+     make the TLS routines happy.  */
+  static_map.l_tls_align = align;
+  static_map.l_tls_blocksize = memsz;
+  static_map.l_tls_initimage = initimage;
+  static_map.l_tls_initimage_size = filesz;
+  static_map.l_type = lt_executable;
+  static_map.l_tls_modid = 1;
+
+  init_slotinfo ();
+  // static_slotinfo.si.slotinfo[1].gen = 0; already zero
+  static_slotinfo.si.slotinfo[1].map = &static_map;
+
+  memsz = roundup (memsz, align ?: 1);
+
+# if TLS_TCB_AT_TP
+  memsz += tcbsize;
+# elif TLS_DTV_AT_TP
+  memsz += tcb_offset;
+# endif
+
+  init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
+}
+
+/* This is called only when the data structure setup was skipped at startup,
+   when there was no need for it then.  Now we have dynamically loaded
+   something needing TLS, or libpthread needs it.  */
+int
+internal_function
+_dl_tls_setup (void)
+{
+  init_slotinfo ();
+  init_static_tls (
+# if TLS_TCB_AT_TP
+		   TLS_TCB_SIZE,
+# else
+		   0,
+# endif
+		   TLS_TCB_ALIGN);
+  return 0;
+}
+
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_minimal (void)
+{
+  __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
+}
+
+#elif defined NONTLS_INIT_TP
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_minimal (void)
+{
+  NONTLS_INIT_TP;
+}
+
+#endif
diff --git a/csu/start.c b/csu/start.c
new file mode 100644
index 0000000000..08f985c482
--- /dev/null
+++ b/csu/start.c
@@ -0,0 +1,13 @@
+/* This file should define the low-level program entry point,
+   which should set up `__environ', and then do:
+     __libc_init(argc, argv, __environ);
+     exit(main(argc, argv, __environ));
+
+   This file should be prepared to be the first thing in the text section (on
+   Unix systems), or otherwise appropriately special.  */
+
+/* The first piece of initialized data.  */
+int __data_start = 0;
+#ifdef HAVE_WEAK_SYMBOLS
+weak_alias (__data_start, data_start)
+#endif
diff --git a/csu/sysdep.c b/csu/sysdep.c
new file mode 100644
index 0000000000..5442eee00d
--- /dev/null
+++ b/csu/sysdep.c
@@ -0,0 +1,2 @@
+/* This file should contain any system-dependent functions
+   that will be used by many parts of the library.  */