/* Run time dynamic linker.
Copyright (C) 1995-2002, 2003, 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 <dlfcn.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h> /* Check if MAP_ANON is defined. */
#include <sys/param.h>
#include <sys/stat.h>
#include <ldsodefs.h>
#include <stdio-common/_itoa.h>
#include <entry.h>
#include <fpu_control.h>
#include <hp-timing.h>
#include <bits/libc-lock.h>
#include "dynamic-link.h"
#include "dl-librecon.h"
#include <unsecvars.h>
#include <dl-cache.h>
#include <dl-procinfo.h>
#include <tls.h>
#include <assert.h>
/* Avoid PLT use for our local calls at startup. */
extern __typeof (__mempcpy) __mempcpy attribute_hidden;
/* GCC has mental blocks about _exit. */
extern __typeof (_exit) exit_internal asm ("_exit") attribute_hidden;
#define _exit exit_internal
/* Helper function to handle errors while resolving symbols. */
static void print_unresolved (int errcode, const char *objname,
const char *errsting);
/* Helper function to handle errors when a version is missing. */
static void print_missing_version (int errcode, const char *objname,
const char *errsting);
/* Print the various times we collected. */
static void print_statistics (hp_timing_t *total_timep);
/* This is a list of all the modes the dynamic loader can be in. */
enum mode { normal, list, verify, trace };
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
static void process_envvars (enum mode *modep);
int _dl_argc attribute_relro attribute_hidden;
#ifdef DL_ARGV_NOT_RELRO
char **_dl_argv = NULL;
#else
char **_dl_argv attribute_relro = NULL;
#endif
INTDEF(_dl_argv)
/* Nonzero if we were run directly. */
unsigned int _dl_skip_args attribute_relro attribute_hidden;
#ifndef HAVE_INLINED_SYSCALLS
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
must not be initialized to nonzero, because the unused dynamic
linker loaded in for libc.so's "ld.so.1" dep will provide the
definition seen by libc.so's initializer; that value must be zero,
and will be since that dynamic linker's _dl_start and dl_main will
never be called. */
int _dl_starting_up = 0;
INTVARDEF(_dl_starting_up)
#endif
/* This is the structure which defines all variables global to ld.so
(except those which cannot be added for some reason). */
struct rtld_global _rtld_global =
{
/* Default presumption without further information is executable stack. */
._dl_stack_flags = PF_R|PF_W|PF_X,
#ifdef _LIBC_REENTRANT
._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER
#endif
};
/* If we would use strong_alias here the compiler would see a
non-hidden definition. This would undo the effect of the previous
declaration. So spell out was strong_alias does plus add the
visibility attribute. */
extern struct rtld_global _rtld_local
__attribute__ ((alias ("_rtld_global"), visibility ("hidden")));
/* This variable is similar to _rtld_local, but all values are
read-only after relocation. */
struct rtld_global_ro _rtld_global_ro attribute_relro =
{
/* Get architecture specific initializer. */
#include <dl-procinfo.c>
#ifdef NEED_DL_SYSINFO
._dl_sysinfo = DL_SYSINFO_DEFAULT,
#endif
._dl_debug_fd = STDERR_FILENO,
._dl_use_load_bias = -2,
._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID,
._dl_hwcap_mask = HWCAP_IMPORTANT,
._dl_lazy = 1,
._dl_fpu_control = _FPU_DEFAULT,
/* Function pointers. */
._dl_get_origin = _dl_get_origin,
._dl_dst_count = _dl_dst_count,
._dl_dst_substitute = _dl_dst_substitute,
._dl_map_object = _dl_map_object,
._dl_map_object_deps = _dl_map_object_deps,
._dl_relocate_object = _dl_relocate_object,
._dl_check_map_versions = _dl_check_map_versions,
._dl_init = _dl_init,
._dl_debug_state = _dl_debug_state,
#ifndef MAP_COPY
._dl_unload_cache = _dl_unload_cache,
#endif
._dl_debug_printf = _dl_debug_printf,
._dl_catch_error = _dl_catch_error,
._dl_signal_error = _dl_signal_error,
._dl_start_profile = _dl_start_profile,
._dl_mcount = _dl_mcount_internal,
._dl_lookup_symbol_x = _dl_lookup_symbol_x,
._dl_check_caller = _dl_check_caller
};
/* If we would use strong_alias here the compiler would see a
non-hidden definition. This would undo the effect of the previous
declaration. So spell out was strong_alias does plus add the
visibility attribute. */
extern struct rtld_global_ro _rtld_local_ro
__attribute__ ((alias ("_rtld_global_ro"), visibility ("hidden")));
static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
ElfW(Addr) *user_entry);
/* These two variables cannot be moved into .data.rel.ro. */
static struct libname_list _dl_rtld_libname;
static struct libname_list _dl_rtld_libname2;
/* We expect less than a second for relocation. */
#ifdef HP_SMALL_TIMING_AVAIL
# undef HP_TIMING_AVAIL
# define HP_TIMING_AVAIL HP_SMALL_TIMING_AVAIL
#endif
/* Variable for statistics. */
#ifndef HP_TIMING_NONAVAIL
static hp_timing_t relocate_time;
static hp_timing_t load_time attribute_relro;
static hp_timing_t start_time attribute_relro;
#endif
/* Additional definitions needed by TLS initialization. */
#ifdef TLS_INIT_HELPER
TLS_INIT_HELPER
#endif
/* Helper function for syscall implementation. */
#ifdef DL_SYSINFO_IMPLEMENTATION
DL_SYSINFO_IMPLEMENTATION
#endif
/* Before ld.so is relocated we must not access variables which need
relocations. This means variables which are exported. Variables
declared as static are fine. If we can mark a variable hidden this
is fine, too. The latter is important here. We can avoid setting
up a temporary link map for ld.so if we can mark _rtld_global as
hidden. */
#if defined PI_STATIC_AND_HIDDEN && defined HAVE_HIDDEN \
&& defined HAVE_VISIBILITY_ATTRIBUTE
# define DONT_USE_BOOTSTRAP_MAP 1
#endif
#ifdef DONT_USE_BOOTSTRAP_MAP
static ElfW(Addr) _dl_start_final (void *arg);
#else
struct dl_start_final_info
{
struct link_map l;
#if !defined HP_TIMING_NONAVAIL && HP_TIMING_INLINE
hp_timing_t start_time;
#endif
};
static ElfW(Addr) _dl_start_final (void *arg,
struct dl_start_final_info *info);
#endif
/* These defined magically in the linker script. */
extern char _begin[] attribute_hidden;
extern char _etext[] attribute_hidden;
extern char _end[] attribute_hidden;
#ifdef RTLD_START
RTLD_START
#else
# error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START"
#endif
#ifndef VALIDX
# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALTAGIDX (tag))
#endif
#ifndef ADDRIDX
# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag))
#endif
/* This is the second half of _dl_start (below). It can be inlined safely
under DONT_USE_BOOTSTRAP_MAP, where it is careful not to make any GOT
references. When the tools don't permit us to