diff options
Diffstat (limited to 'csu')
-rw-r--r-- | csu/Makefile | 30 | ||||
-rw-r--r-- | csu/check_fds.c | 102 | ||||
-rw-r--r-- | csu/dso_handle.c | 5 | ||||
-rw-r--r-- | csu/elf-init.c | 59 | ||||
-rw-r--r-- | csu/errno-loc.c (renamed from csu/munch-tmpl.c) | 33 | ||||
-rw-r--r-- | csu/errno.c | 53 | ||||
-rw-r--r-- | csu/init-first.c | 59 | ||||
-rw-r--r-- | csu/libc-start.c | 263 | ||||
-rw-r--r-- | csu/libc-tls.c | 263 | ||||
-rw-r--r-- | csu/munch.awk | 11 | ||||
-rw-r--r-- | csu/start.c | 13 | ||||
-rw-r--r-- | csu/sysdep.c | 2 | ||||
-rw-r--r-- | csu/version.c | 4 |
13 files changed, 824 insertions, 73 deletions
diff --git a/csu/Makefile b/csu/Makefile index fbbfe00..0e2ae07 100644 --- a/csu/Makefile +++ b/csu/Makefile @@ -1,5 +1,5 @@ # Makefile for csu code for GNU C library. -# Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc. +# Copyright (C) 1995-2004, 2005, 2006 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 @@ -39,8 +39,8 @@ omit-deps = $(patsubst %.o,%,$(start-installed-name) g$(start-installed-name) \ b$(start-installed-name) $(csu-dummies) \ S$(start-installed-name)) install-lib = $(start-installed-name) g$(start-installed-name) $(csu-dummies) -distribute = initfini.c gmon-start.c start.c defs.awk munch.awk \ - abi-note.S init.c munch-tmpl.c not-cancel.h +distribute = initfini.c gmon-start.c start.c defs.awk \ + abi-note.S init.c c not-cancel.h generated = version-info.h before-compile = $(objpfx)version-info.h @@ -54,11 +54,13 @@ include ../Makeconfig ifeq (yes,$(build-shared)) extra-objs += S$(start-installed-name) install-lib += S$(start-installed-name) +generated += start.os endif ifeq (yes,$(build-bounded)) extra-objs += b$(start-installed-name) install-lib += b$(start-installed-name) +generated += start.ob endif ifneq ($(start-installed-name),$(static-start-installed-name)) @@ -73,19 +75,6 @@ before-compile += $(objpfx)abi-tag.h generated += abi-tag.h endif -ifneq (yes,$(gnu-ld)) -libc-init = munch-init -$(objpfx)munch-init.c: munch.awk munch-tmpl.c $(+subdir_inits) - $(AWK) -f $< subdirs='$(+init_subdirs)' $(word 2,$^) > $@-t - mv -f $@-t $@ -generated += munch-init.c - -# All initialization source files. -+subdir_inits := $(wildcard $(foreach dir,$(subdirs),$(dir)/init-$(dir).c)) -# All subdirectories containing initialization source files. -+init_subdirs := $(patsubst %/,%,$(dir $(+subdir_inits))) -endif - ifeq ($(have-initfini),yes) CPPFLAGS += -DHAVE_INITFINI @@ -106,7 +95,7 @@ $(crtstuff:%=$(objpfx)%.o): %.o: %.S $(objpfx)defs.h CFLAGS-initfini.s = -g0 -fPIC -fno-inline-functions $(fno-unit-at-a-time) -vpath initfini.c $(full_config_sysdirs) +vpath initfini.c $(sysdirs) $(objpfx)initfini.s: initfini.c $(before-compile) $(compile.c) -S $(CFLAGS-initfini.s) -finhibit-size-directive \ @@ -211,8 +200,9 @@ $(objpfx)abi-tag.h: $(..)abi-tags if test -r $@.new; then mv -f $@.new $@; \ else echo >&2 'This configuration not matched in $<'; exit 1; fi -all-Banner-files = $(wildcard $(addsuffix /Banner, \ - $(addprefix $(..), $(subdirs)))) +all-Banner-files = $(wildcard $(addsuffix /Banner,\ + $(sort $(subdir-srcdirs) \ + $(sysdeps-srcdirs)))) $(objpfx)version-info.h: $(common-objpfx)config.make $(all-Banner-files) $(make-target-directory) (case $(config-os) in \ @@ -239,7 +229,7 @@ $(objpfx)version-info.h: $(common-objpfx)config.make $(all-Banner-files) esac; \ files="$(all-Banner-files)"; \ if test -n "$$files"; then \ - echo "\"Available extensions:\\n\""; \ + printf '"Available extensions:\\n"\n'; \ sed -e '/^#/d' -e 's/^[[:space:]]*/ /' \ -e 's/^\(.*\)$$/\"\1\\n\"/' $$files; \ fi) > $@T diff --git a/csu/check_fds.c b/csu/check_fds.c new file mode 100644 index 0000000..10ba3da --- /dev/null +++ b/csu/check_fds.c @@ -0,0 +1,102 @@ +/* Copyright (C) 2000, 2002, 2003, 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 <fcntl.h> +#include <paths.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> + +/* Try to get a machine dependent instruction which will make the + program crash. This is used in case everything else fails. */ +#include <abort-instr.h> +#ifndef ABORT_INSTRUCTION +/* No such instruction is available. */ +# define ABORT_INSTRUCTION +#endif + +#include <device-nrs.h> +#include <not-cancel.h> + + +/* Should other OSes (e.g., Hurd) have different versions which can + be written in a better way? */ +static void +check_one_fd (int fd, int mode) +{ + /* Note that fcntl() with this parameter is not a cancellation point. */ + if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1 + && errno == EBADF) + { + const char *name; + dev_t dev; + + /* For writable descriptors we use /dev/full. */ + if ((mode & O_ACCMODE) == O_WRONLY) + { + name = _PATH_DEV "full"; + dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR); + } + else + { + name = _PATH_DEVNULL; + dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR); + } + + /* Something is wrong with this descriptor, it's probably not + opened. Open /dev/null so that the SUID program we are + about to start does not accidently use this descriptor. */ + int nullfd = open_not_cancel (name, mode, 0); + + /* We are very paranoid here. With all means we try to ensure + that we are actually opening the /dev/null device and nothing + else. + + Note that the following code assumes that STDIN_FILENO, + STDOUT_FILENO, STDERR_FILENO are the three lowest file + decsriptor numbers, in this order. */ + struct stat64 st; + if (__builtin_expect (nullfd != fd, 0) + || __builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) != 0 + || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0 + || st.st_rdev != dev) + /* We cannot even give an error message here since it would + run into the same problems. */ + while (1) + /* Try for ever and ever. */ + ABORT_INSTRUCTION; + } +} + + +void +__libc_check_standard_fds (void) +{ + /* This is really paranoid but some people actually are. If /dev/null + should happen to be a symlink to somewhere else and not the device + commonly known as "/dev/null" we bail out. We can detect this with + the O_NOFOLLOW flag for open() but only on some system. */ +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif + /* Check all three standard file descriptors. */ + check_one_fd (STDIN_FILENO, O_WRONLY | O_NOFOLLOW); + check_one_fd (STDOUT_FILENO, O_RDONLY | O_NOFOLLOW); + check_one_fd (STDERR_FILENO, O_RDONLY | O_NOFOLLOW); +} diff --git a/csu/dso_handle.c b/csu/dso_handle.c index 04ed078..fd295f2 100644 --- a/csu/dso_handle.c +++ b/csu/dso_handle.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002, 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 @@ -18,4 +18,5 @@ /* We have to define __dso_handle ourselves since we do not use gcc's crtbegin files. */ -void *__dso_handle __attribute__ ((__visibility__ ("hidden"))) = &__dso_handle; +const void *const __dso_handle __attribute__ ((__visibility__ ("hidden"))) + = &__dso_handle; diff --git a/csu/elf-init.c b/csu/elf-init.c index d4e0b3f..d0a518f 100644 --- a/csu/elf-init.c +++ b/csu/elf-init.c @@ -1,5 +1,5 @@ /* Startup support for ELF initializers/finalizers in the main executable. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + 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 @@ -36,16 +36,37 @@ #include <stddef.h> -#ifdef HAVE_INITFINI_ARRAY + /* These magic symbols are provided by the linker. */ -extern void (*__preinit_array_start []) (void) attribute_hidden; -extern void (*__preinit_array_end []) (void) attribute_hidden; -extern void (*__init_array_start []) (void) attribute_hidden; -extern void (*__init_array_end []) (void) attribute_hidden; +extern void (*__preinit_array_start []) (int, char **, char **) + attribute_hidden; +extern void (*__preinit_array_end []) (int, char **, char **) + attribute_hidden; +extern void (*__init_array_start []) (int, char **, char **) + attribute_hidden; +extern void (*__init_array_end []) (int, char **, char **) + attribute_hidden; extern void (*__fini_array_start []) (void) attribute_hidden; extern void (*__fini_array_end []) (void) attribute_hidden; + +#if defined HAVE_VISIBILITY_ATTRIBUTE \ + && (defined SHARED || defined LIBC_NONSHARED) +# define hidden_undef_2(x) #x +# define hidden_undef_1(x) hidden_undef_2 (x) +# define hidden_undef(x) \ + __asm (hidden_undef_1 (ASM_GLOBAL_DIRECTIVE) " " #x); \ + __asm (".hidden " #x); +#else +# define hidden_undef(x) #endif +hidden_undef (__preinit_array_start) +hidden_undef (__preinit_array_end) +hidden_undef (__init_array_start) +hidden_undef (__init_array_end) +hidden_undef (__fini_array_start) +hidden_undef (__fini_array_end) + /* These function symbols are provided for the .init/.fini section entry points automagically by the linker. */ extern void _init (void); @@ -57,43 +78,39 @@ extern void _fini (void); the libc.a module in that it doesn't call the preinit array. */ void -__libc_csu_init (void) +__libc_csu_init (int argc, char **argv, char **envp) { -#ifdef HAVE_INITFINI_ARRAY /* For dynamically linked executables the preinit array is executed by the dynamic linker (before initializing any shared object. */ -# ifndef LIBC_NONSHARED +#ifndef LIBC_NONSHARED /* For static executables, preinit happens rights before init. */ { const size_t size = __preinit_array_end - __preinit_array_start; size_t i; for (i = 0; i < size; i++) - (*__preinit_array_start [i]) (); + (*__preinit_array_start [i]) (argc, argv, envp); } -# endif #endif _init (); -#ifdef HAVE_INITFINI_ARRAY - { - const size_t size = __init_array_end - __init_array_start; - size_t i; - for (i = 0; i < size; i++) - (*__init_array_start [i]) (); - } -#endif + const size_t size = __init_array_end - __init_array_start; + for (size_t i = 0; i < size; i++) + (*__init_array_start [i]) (argc, argv, envp); } +/* This function should not be used anymore. We run the executable's + destructor now just like any other. We cannot remove the function, + though. */ void __libc_csu_fini (void) { -#ifdef HAVE_INITFINI_ARRAY +#ifndef LIBC_NONSHARED size_t i = __fini_array_end - __fini_array_start; while (i-- > 0) (*__fini_array_start [i]) (); -#endif _fini (); +#endif } diff --git a/csu/munch-tmpl.c b/csu/errno-loc.c index f807cf9..633590f 100644 --- a/csu/munch-tmpl.c +++ b/csu/errno-loc.c @@ -1,4 +1,6 @@ -/* Copyright (C) 1991, 1995, 1997, 2000 Free Software Foundation, Inc. +/* MT support function to get address of `errno' variable, non-threaded + version. + Copyright (C) 1996, 1998, 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 @@ -16,23 +18,20 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <stdlib.h> +#include <errno.h> +#include <tls.h> +#if ! USE___THREAD && !RTLD_PRIVATE_ERRNO +#undef errno +extern int errno; +#endif -EXTERNS - -void -__libc_init (int argc, char **argv, char **envp) -{ - CALLS - -#ifdef HAVE_INITFINI - { - /* These functions are defined in crti.o to run the .init and .fini - sections, which are used for initializers and finalizers. */ - extern void _init (void), _fini (void); - atexit (&_fini); /* Arrange for _fini to run at exit. */ - _init (); - } +int * +#if ! USE___THREAD +weak_const_function #endif +__errno_location (void) +{ + return &errno; } +libc_hidden_def (__errno_location) diff --git a/csu/errno.c b/csu/errno.c new file mode 100644 index 0000000..03d661b --- /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 0000000..fa21274 --- /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 0000000..194db6b --- /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 0000000..3544e39 --- /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/munch.awk b/csu/munch.awk deleted file mode 100644 index 9ebcff8..0000000 --- a/csu/munch.awk +++ /dev/null @@ -1,11 +0,0 @@ -BEGIN { special = 0 } - -/EXTERNS/ { ndirs = split(subdirs, dirs) - for (i = 1; i <= ndirs; ++i) - printf "extern void __init_%s (int argc, char **argv, char **envp);\n", dirs[i] - special = 1 } -/CALLS/ { ndirs = split(subdirs, dirs) - for (i = 1; i <= ndirs; ++i) printf " __init_%s (argc, argv, envp);\n", dirs[i] - special = 1 } - -{ if (special == 0) print $0; special = 0 } diff --git a/csu/start.c b/csu/start.c new file mode 100644 index 0000000..08f985c --- /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 0000000..5442eee --- /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. */ diff --git a/csu/version.c b/csu/version.c index 1104fa9..2196d20 100644 --- a/csu/version.c +++ b/csu/version.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1992-2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1992-2002, 2003, 2004, 2006 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 @@ -25,7 +25,7 @@ static const char __libc_version[] = VERSION; static const char banner[] = "GNU C Library "RELEASE" release version "VERSION", by Roland McGrath et al.\n\ -Copyright (C) 2004 Free Software Foundation, Inc.\n\ +Copyright (C) 2006 Free Software Foundation, Inc.\n\ This is free software; see the source for copying conditions.\n\ There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ PARTICULAR PURPOSE.\n\ |