mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
* csu/elf-init.c (__libc_csu_fini): Don't do anything here.
* sysdeps/generic/libc-start.c: Don't register program destructor here. * dlfcn/Makefile: Add rules to build dlfcn.c. (LDFLAGS-dl.so): Removed. * dlfcn/dlclose.c: _dl_close is now in ld.so, use function pointer table. * dlfcn/dlmopen.c: Likewise for _dl_open. * dlfcn/dlopen.c: Likewise. * dlfcn/dlopenold.c: Likewise. * elf/dl-libc.c: Likewise for _dl_open and _dl_close. * elf/Makefile (routines): Remove dl-open and dl-close. (dl-routines): Add dl-open, dl-close, and dl-trampoline. Add rules to build and run tst-audit1. * elf/tst-audit1.c: New file. * elf/tst-auditmod1.c: New file. * elf/Versions [libc]: Remove _dl_open and _dl_close. * elf/dl-close.c: Change for use inside ld.so instead of libc.so. * elf/dl-open.c: Likewise. * elf/dl-debug.c (_dl_debug_initialize): Allow reinitialization, signaled by nonzero parameter. * elf/dl-init.c: Fix use of r_state. * elf/dl-load.c: Likewise. * elf/dl-close.c: Add auditing checkpoints. * elf/dl-open.c: Likewise. * elf/dl-fini.c: Likewise. * elf/dl-load.c: Likewise. * elf/dl-sym.c: Likewise. * sysdeps/generic/libc-start.c: Likewise. * elf/dl-object.c: Allocate memory for auditing information. * elf/dl-reloc.c: Remove RESOLV. We now always need the map. Correctly initialize slotinfo. * elf/dynamic-link.h: Adjust after removal of RESOLV. * sysdeps/hppa/dl-lookupcfg.h: Likewise. * sysdeps/ia64/dl-lookupcfg.h: Likewise. * sysdeps/powerpc/powerpc64/dl-lookupcfg.h: Removed. * elf/dl-runtime.c (_dl_fixup): Little cleanup. (_dl_profile_fixup): New parameters to point to register struct and variable for frame size. Add auditing checkpoints. (_dl_call_pltexit): New function. Don't define trampoline code here. * elf/rtld.c: Recognize LD_AUDIT. Load modules on startup. Remove all the functions from _rtld_global_ro which only _dl_open and _dl_close needed. Add auditing checkpoints. * elf/link.h: Define symbols for auditing interfaces. * include/link.h: Likewise. * include/dlfcn.h: Define __RTLD_AUDIT. Remove prototypes for _dl_open and _dl_close. Adjust access to argc and argv in libdl. * dlfcn/dlfcn.c: New file. * sysdeps/generic/dl-lookupcfg.h: Remove all content now that RESOLVE is gone. * sysdeps/generic/ldsodefs.h: Add definitions for auditing interfaces. * sysdeps/generic/unsecvars.h: Add LD_AUDIT. * sysdeps/i386/dl-machine.h: Remove trampoline code here. Adjust for removal of RESOLVE. * sysdeps/x86_64/dl-machine.h: Likewise. * sysdeps/generic/dl-trampoline.c: New file. * sysdeps/i386/dl-trampoline.c: New file. * sysdeps/x86_64/dl-trampoline.c: New file. * sysdeps/generic/dl-tls.c: Cleanups. Fixup for dtv_t change. Fix updating of DTV. * sysdeps/generic/libc-tls.c: Likewise. * sysdeps/arm/bits/link.h: Renamed to ... * sysdeps/arm/buts/linkmap.h: ...this. * sysdeps/generic/bits/link.h: Renamed to... * sysdeps/generic/bits/linkmap.h: ...this. * sysdeps/hppa/bits/link.h: Renamed to... * sysdeps/hppa/bits/linkmap.h: ...this. * sysdeps/hppa/i386/link.h: Renamed to... * sysdeps/hppa/i386/linkmap.h: ...this. * sysdeps/hppa/ia64/link.h: Renamed to... * sysdeps/hppa/ia64/linkmap.h: ...this. * sysdeps/hppa/s390/link.h: Renamed to... * sysdeps/hppa/s390/linkmap.h: ...this. * sysdeps/hppa/sh/link.h: Renamed to... * sysdeps/hppa/sh/linkmap.h: ...this. * sysdeps/hppa/x86_64/link.h: Renamed to... * sysdeps/hppa/x86_64/linkmap.h: ...this. 2005-01-06 Ulrich Drepper <drepper@redhat.com> * allocatestack.c (init_one_static_tls): Adjust initialization of DTV entry for static tls deallocation fix. * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which also contains information whether the memory pointed to is static TLS or not. * sysdeps/i386/tls.h: Likewise. * sysdeps/ia64/tls.h: Likewise. * sysdeps/powerpc/tls.h: Likewise. * sysdeps/s390/tls.h: Likewise. * sysdeps/sh/tls.h: Likewise. * sysdeps/sparc/tls.h: Likewise. * sysdeps/x86_64/tls.h: Likewise.
This commit is contained in:
parent
f14038f2e2
commit
9dcafc5597
@ -1,4 +1 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
/* empty by default */
|
||||
};
|
||||
#error "Architecture-specific definition needed."
|
||||
|
4
bits/linkmap.h
Normal file
4
bits/linkmap.h
Normal file
@ -0,0 +1,4 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
/* empty by default */
|
||||
};
|
@ -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
|
||||
@ -86,9 +86,13 @@ __libc_csu_init (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
#if 0
|
||||
#ifdef HAVE_INITFINI_ARRAY
|
||||
size_t i = __fini_array_end - __fini_array_start;
|
||||
while (i-- > 0)
|
||||
@ -96,4 +100,5 @@ __libc_csu_fini (void)
|
||||
#endif
|
||||
|
||||
_fini ();
|
||||
#endif
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ subdir := dlfcn
|
||||
headers := bits/dlfcn.h dlfcn.h
|
||||
extra-libs := libdl
|
||||
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
|
||||
dlmopen
|
||||
routines := $(patsubst %,s%,$(libdl-routines))
|
||||
dlmopen dlfcn
|
||||
routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines)))
|
||||
elide-routines.os := $(routines)
|
||||
distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
|
||||
defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
|
||||
@ -34,7 +34,7 @@ include ../Makeconfig
|
||||
|
||||
ifeq ($(versioning),yes)
|
||||
libdl-routines += dlopenold
|
||||
libdl-shared-only-routines := dlopenold
|
||||
libdl-shared-only-routines := dlopenold dlfcn
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
@ -65,8 +65,6 @@ generated := $(modules-names:=.so)
|
||||
|
||||
include ../Rules
|
||||
|
||||
LDFLAGS-dl.so = -Wl,-dynamic-linker,$(slibdir)/$(rtld-installed-name)
|
||||
|
||||
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
||||
$(test-modules): $(objpfx)%.so: $(objpfx)%.os $(common-objpfx)shlib.lds
|
||||
$(build-module)
|
||||
|
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
#if !defined SHARED && defined IS_IN_libdl
|
||||
|
||||
@ -33,7 +34,7 @@ dlclose (void *handle)
|
||||
static void
|
||||
dlclose_doit (void *handle)
|
||||
{
|
||||
_dl_close (handle);
|
||||
GLRO(dl_close) (handle);
|
||||
}
|
||||
|
||||
int
|
||||
|
33
dlfcn/dlfcn.c
Normal file
33
dlfcn/dlfcn.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* Load a shared object at run time.
|
||||
Copyright (C) 1995,96,97,98,99,2000,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 <dlfcn.h>
|
||||
|
||||
|
||||
int __dlfcn_argc attribute_hidden;
|
||||
char **__dlfcn_argv attribute_hidden;
|
||||
|
||||
|
||||
void
|
||||
__attribute ((constuctor))
|
||||
init (int argc, char *argv[])
|
||||
{
|
||||
__dlfcn_argc = argc;
|
||||
__dlfcn_argv = argv;
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
#if !defined SHARED && defined IS_IN_libdl
|
||||
@ -61,8 +62,10 @@ dlmopen_doit (void *a)
|
||||
# endif
|
||||
GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
|
||||
|
||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller, args->nsid);
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->nsid, __dlfcn_argc, __dlfcn_argv,
|
||||
__environ);
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
#if !defined SHARED && defined IS_IN_libdl
|
||||
|
||||
@ -56,8 +58,10 @@ dlopen_doit (void *a)
|
||||
{
|
||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||
|
||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller, args->file == NULL ? LM_ID_BASE : NS);
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->file == NULL ? LM_ID_BASE : NS,
|
||||
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
/* This file is for compatibility with glibc 2.0. Compile it only if
|
||||
versioning is used. */
|
||||
@ -50,8 +52,10 @@ dlopen_doit (void *a)
|
||||
{
|
||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||
|
||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller, args->file == NULL ? LM_ID_BASE : NS);
|
||||
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||
args->caller,
|
||||
args->file == NULL ? LM_ID_BASE : NS,
|
||||
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||
}
|
||||
|
||||
extern void *__dlopen_nocheck (const char *file, int mode);
|
||||
|
15
elf/Makefile
15
elf/Makefile
@ -21,7 +21,7 @@
|
||||
subdir := elf
|
||||
|
||||
headers = elf.h bits/elfclass.h link.h
|
||||
routines = $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
|
||||
routines = $(dl-routines) dl-support dl-iteratephdr \
|
||||
dl-addr enbl-secure dl-profstub \
|
||||
dl-origin dl-libc dl-sym dl-tsd
|
||||
|
||||
@ -30,7 +30,7 @@ routines = $(dl-routines) dl-open dl-close dl-support dl-iteratephdr \
|
||||
dl-routines = $(addprefix dl-,load cache lookup object reloc deps \
|
||||
runtime error init fini debug misc \
|
||||
version profile conflict tls origin \
|
||||
execstack caller)
|
||||
execstack caller open close trampoline)
|
||||
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
|
||||
# But they are absent from the shared libc, because that code is in ld.so.
|
||||
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin
|
||||
@ -83,7 +83,8 @@ distribute := rtld-Rules \
|
||||
tst-array2dep.c tst-piemod1.c \
|
||||
tst-execstack-mod.c tst-dlmodcount.c \
|
||||
check-textrel.c dl-sysdep.h test-dlopenrpathmod.c \
|
||||
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c
|
||||
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c \
|
||||
tst-auditmod1.c
|
||||
|
||||
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
|
||||
@ -154,7 +155,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
|
||||
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
|
||||
$(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
|
||||
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3
|
||||
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
|
||||
tst-audit1
|
||||
# reldep9
|
||||
test-srcs = tst-pathopt
|
||||
tests-vis-yes = vismain
|
||||
@ -188,7 +190,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
reldep9mod1 reldep9mod2 reldep9mod3 \
|
||||
tst-alignmod $(modules-execstack-$(have-z-execstack)) \
|
||||
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
|
||||
tst-dlmopen1mod
|
||||
tst-dlmopen1mod tst-auditmod1
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
modules-names += tst-array2dep
|
||||
endif
|
||||
@ -773,3 +775,6 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-dlmopen3: $(libdl)
|
||||
$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
|
||||
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
|
@ -19,7 +19,7 @@ libc {
|
||||
%endif
|
||||
GLIBC_PRIVATE {
|
||||
# functions used in other libraries
|
||||
_dl_open; _dl_close; _dl_addr;
|
||||
_dl_addr;
|
||||
_dl_sym; _dl_vsym;
|
||||
_dl_open_hook;
|
||||
__libc_dlopen_mode; __libc_dlsym; __libc_dlclose;
|
||||
|
110
elf/dl-close.c
110
elf/dl-close.c
@ -23,6 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <bits/libc-lock.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <sys/types.h>
|
||||
@ -99,7 +100,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
|
||||
|
||||
|
||||
void
|
||||
internal_function
|
||||
_dl_close (void *_map)
|
||||
{
|
||||
struct reldep_list
|
||||
@ -112,6 +112,7 @@ _dl_close (void *_map)
|
||||
} *reldeps = NULL;
|
||||
struct link_map **list;
|
||||
struct link_map *map = _map;
|
||||
Lmid_t ns = map->l_ns;
|
||||
unsigned int i;
|
||||
unsigned int *new_opencount;
|
||||
#ifdef USE_TLS
|
||||
@ -139,8 +140,8 @@ _dl_close (void *_map)
|
||||
{
|
||||
/* There are still references to this object. Do nothing more. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("\nclosing file=%s; opencount == %u\n",
|
||||
map->l_name, map->l_opencount);
|
||||
_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
|
||||
map->l_name, map->l_opencount);
|
||||
|
||||
/* Decrement the object's reference counter, not the dependencies'. */
|
||||
--map->l_opencount;
|
||||
@ -268,13 +269,17 @@ _dl_close (void *_map)
|
||||
for (i = 0; list[i] != NULL; ++i)
|
||||
{
|
||||
struct link_map *imap = list[i];
|
||||
|
||||
/* All elements must be in the same namespace. */
|
||||
assert (imap->l_ns == ns);
|
||||
|
||||
if (new_opencount[i] == 0 && imap->l_type == lt_loaded
|
||||
&& (imap->l_flags_1 & DF_1_NODELETE) == 0)
|
||||
{
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
|
||||
imap->l_name, imap->l_ns);
|
||||
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||
imap->l_name, ns);
|
||||
|
||||
/* Call its termination function. Do not do it for
|
||||
half-cooked objects. */
|
||||
@ -299,6 +304,22 @@ _dl_close (void *_map)
|
||||
+ imap->l_info[DT_FINI]->d_un.d_ptr))) ();
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have a new object. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->objclose != NULL)
|
||||
/* Return value is ignored. */
|
||||
(void) afct->objclose (&imap->l_audit[cnt].cookie);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This object must not be used anymore. We must remove the
|
||||
reference from the scope. */
|
||||
unsigned int j;
|
||||
@ -365,9 +386,30 @@ _dl_close (void *_map)
|
||||
assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we will start deleting objects. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct link_map *head = GL(dl_ns)[ns]._ns_loaded;
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
/* Do not call the functions for any auditing object. */
|
||||
if (head->l_auditing == 0)
|
||||
{
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->activity != NULL)
|
||||
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_DELETE);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Notify the debugger we are about to remove some loaded objects. */
|
||||
_r_debug.r_state = RT_DELETE;
|
||||
GLRO(dl_debug_state) ();
|
||||
struct r_debug *r = _dl_debug_initialize (0);
|
||||
r->r_state = RT_DELETE;
|
||||
_dl_debug_state ();
|
||||
|
||||
#ifdef USE_TLS
|
||||
size_t tls_free_start;
|
||||
@ -389,21 +431,19 @@ _dl_close (void *_map)
|
||||
if (__builtin_expect (imap->l_global, 0))
|
||||
{
|
||||
/* This object is in the global scope list. Remove it. */
|
||||
unsigned int cnt
|
||||
= GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
|
||||
unsigned int cnt = GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
|
||||
|
||||
do
|
||||
--cnt;
|
||||
while (GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt]
|
||||
!= imap);
|
||||
while (GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt] != imap);
|
||||
|
||||
/* The object was already correctly registered. */
|
||||
while (++cnt
|
||||
< GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist)
|
||||
GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt - 1]
|
||||
= GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt];
|
||||
< GL(dl_ns)[ns]._ns_main_searchlist->r_nlist)
|
||||
GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt - 1]
|
||||
= GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt];
|
||||
|
||||
--GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
|
||||
--GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
@ -412,9 +452,10 @@ _dl_close (void *_map)
|
||||
{
|
||||
any_tls = true;
|
||||
|
||||
if (! remove_slotinfo (imap->l_tls_modid,
|
||||
GL(dl_tls_dtv_slotinfo_list), 0,
|
||||
imap->l_init_called))
|
||||
if (GL(dl_tls_dtv_slotinfo_list) != NULL
|
||||
&& ! remove_slotinfo (imap->l_tls_modid,
|
||||
GL(dl_tls_dtv_slotinfo_list), 0,
|
||||
imap->l_init_called))
|
||||
/* All dynamically loaded modules with TLS are unloaded. */
|
||||
GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
|
||||
|
||||
@ -499,12 +540,12 @@ _dl_close (void *_map)
|
||||
else
|
||||
{
|
||||
#ifdef SHARED
|
||||
assert (imap->l_ns != LM_ID_BASE);
|
||||
assert (ns != LM_ID_BASE);
|
||||
#endif
|
||||
GL(dl_ns)[imap->l_ns]._ns_loaded = imap->l_next;
|
||||
GL(dl_ns)[ns]._ns_loaded = imap->l_next;
|
||||
}
|
||||
|
||||
--GL(dl_ns)[imap->l_ns]._ns_nloaded;
|
||||
--GL(dl_ns)[ns]._ns_nloaded;
|
||||
if (imap->l_next != NULL)
|
||||
imap->l_next->l_prev = imap->l_prev;
|
||||
|
||||
@ -579,16 +620,36 @@ _dl_close (void *_map)
|
||||
if (any_tls)
|
||||
{
|
||||
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
__libc_fatal (_("TLS generation counter wrapped! Please report as described in <http://www.gnu.org/software/libc/bugs.html>."));
|
||||
_dl_fatal_printf ("TLS generation counter wrapped! Please report as described in <http://www.gnu.org/software/libc/bugs.html>.\n");
|
||||
|
||||
if (tls_free_end == GL(dl_tls_static_used))
|
||||
GL(dl_tls_static_used) = tls_free_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have deleted all objects. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct link_map *head = GL(dl_ns)[ns]._ns_loaded;
|
||||
/* Do not call the functions for any auditing object. */
|
||||
if (head->l_auditing == 0)
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->activity != NULL)
|
||||
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Notify the debugger those objects are finalized and gone. */
|
||||
_r_debug.r_state = RT_CONSISTENT;
|
||||
GLRO(dl_debug_state) ();
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
|
||||
/* Now we can perhaps also remove the modules for which we had
|
||||
dependencies because of symbol lookup. */
|
||||
@ -612,7 +673,6 @@ _dl_close (void *_map)
|
||||
/* Release the lock. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
libc_hidden_def (_dl_close)
|
||||
|
||||
|
||||
#ifdef USE_TLS
|
||||
|
@ -34,7 +34,7 @@ struct r_debug *
|
||||
internal_function
|
||||
_dl_debug_initialize (ElfW(Addr) ldbase)
|
||||
{
|
||||
if (_r_debug.r_brk == 0)
|
||||
if (_r_debug.r_brk == 0 || ldbase != 0)
|
||||
{
|
||||
/* Tell the debugger where to find the map of loaded objects. */
|
||||
_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
|
||||
|
@ -53,7 +53,12 @@ _dl_fini (void)
|
||||
/* Protect against concurrent loads and unloads. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
unsigned int nmaps = 0;
|
||||
unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded;
|
||||
/* No need to do anything for empty namespaces or those used for
|
||||
auditing DSOs. */
|
||||
if (nloaded == 0 || GL(dl_ns)[cnt]._ns_loaded->l_auditing)
|
||||
goto out;
|
||||
|
||||
/* XXX Could it be (in static binaries) that there is no object
|
||||
loaded? */
|
||||
@ -76,6 +81,7 @@ _dl_fini (void)
|
||||
|
||||
unsigned int i;
|
||||
struct link_map *l;
|
||||
assert (nloaded != 0 || GL(dl_ns)[cnt]._ns_loaded == NULL);
|
||||
for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
|
||||
/* Do not handle ld.so in secondary namespaces. */
|
||||
if (l == l->l_real)
|
||||
@ -90,7 +96,7 @@ _dl_fini (void)
|
||||
}
|
||||
assert (cnt != LM_ID_BASE || i == nloaded);
|
||||
assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
||||
unsigned int nmaps = i;
|
||||
nmaps = i;
|
||||
|
||||
if (nmaps != 0)
|
||||
{
|
||||
@ -163,6 +169,7 @@ _dl_fini (void)
|
||||
high and will be decremented in this loop. So we release the
|
||||
lock so that some code which might be called from a destructor
|
||||
can directly or indirectly access the lock. */
|
||||
out:
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
|
||||
/* 'maps' now contains the objects in the right order. Now call the
|
||||
@ -176,38 +183,49 @@ _dl_fini (void)
|
||||
/* Make sure nothing happens if we are called twice. */
|
||||
l->l_init_called = 0;
|
||||
|
||||
/* Don't call the destructors for objects we are not
|
||||
supposed to. */
|
||||
if (l->l_name[0] == '\0' && l->l_type == lt_executable)
|
||||
continue;
|
||||
|
||||
/* Is there a destructor function? */
|
||||
if (l->l_info[DT_FINI_ARRAY] == NULL
|
||||
&& l->l_info[DT_FINI] == NULL)
|
||||
continue;
|
||||
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
|
||||
0))
|
||||
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||
l->l_name[0] ? l->l_name : rtld_progname,
|
||||
cnt);
|
||||
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL
|
||||
|| l->l_info[DT_FINI] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
while (i-- > 0)
|
||||
((fini_t) array[i]) ();
|
||||
/* When debugging print a message first. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask)
|
||||
& DL_DEBUG_IMPCALLS, 0))
|
||||
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||
l->l_name[0] ? l->l_name : rtld_progname,
|
||||
cnt);
|
||||
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
while (i-- > 0)
|
||||
((fini_t) array[i]) ();
|
||||
}
|
||||
|
||||
/* Next try the old-style destructor. */
|
||||
if (l->l_info[DT_FINI] != NULL)
|
||||
((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
}
|
||||
|
||||
/* Next try the old-style destructor. */
|
||||
if (l->l_info[DT_FINI] != NULL)
|
||||
((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: another object closed. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->objclose != NULL)
|
||||
/* Return value is ignored. */
|
||||
(void) afct->objclose (&l->l_audit[cnt].cookie);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Correct the previous increment. */
|
||||
|
@ -93,7 +93,6 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
{
|
||||
ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAY];
|
||||
ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
|
||||
struct r_debug *r;
|
||||
unsigned int i;
|
||||
|
||||
if (__builtin_expect (GL(dl_initfirst) != NULL, 0))
|
||||
@ -120,13 +119,6 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
((init_t) addrs[cnt]) (argc, argv, env);
|
||||
}
|
||||
|
||||
/* Notify the debugger we have added some objects. We need to call
|
||||
_dl_debug_initialize in a static program in case dynamic linking has
|
||||
not been used before. */
|
||||
r = _dl_debug_initialize (0);
|
||||
r->r_state = RT_ADD;
|
||||
_dl_debug_state ();
|
||||
|
||||
/* Stupid users forced the ELF specification to be changed. It now
|
||||
says that the dynamic loader is responsible for determining the
|
||||
order in which the constructors have to run. The constructors
|
||||
@ -141,10 +133,6 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
while (i-- > 0)
|
||||
call_init (main_map->l_initfini[i], argc, argv, env);
|
||||
|
||||
/* Notify the debugger all new objects are now ready to go. */
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
|
||||
#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Finished starting up. */
|
||||
INTUSE(_dl_starting_up) = 0;
|
||||
|
@ -22,6 +22,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
extern int __libc_argc attribute_hidden;
|
||||
extern char **__libc_argv attribute_hidden;
|
||||
|
||||
extern char **__environ;
|
||||
|
||||
/* The purpose of this file is to provide wrappers around the dynamic
|
||||
linker error mechanism (similar to dlopen() et al in libdl) which
|
||||
are usable from within libc. Generally we want to throw away the
|
||||
@ -77,7 +82,8 @@ do_dlopen (void *ptr)
|
||||
{
|
||||
struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
|
||||
/* Open and relocate the shared object. */
|
||||
args->map = _dl_open (args->name, args->mode, NULL, __LM_ID_CALLER);
|
||||
args->map = GLRO(dl_open) (args->name, args->mode, NULL, __LM_ID_CALLER,
|
||||
__libc_argc, __libc_argv, __environ);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -93,7 +99,7 @@ do_dlsym (void *ptr)
|
||||
static void
|
||||
do_dlclose (void *ptr)
|
||||
{
|
||||
_dl_close ((struct link_map *) ptr);
|
||||
GLRO(dl_close) ((struct link_map *) ptr);
|
||||
}
|
||||
|
||||
/* This code is to support __libc_dlopen from __libc_dlopen'ed shared
|
||||
@ -109,7 +115,7 @@ struct dl_open_hook
|
||||
#ifdef SHARED
|
||||
extern struct dl_open_hook *_dl_open_hook;
|
||||
libc_hidden_proto (_dl_open_hook);
|
||||
struct dl_open_hook *_dl_open_hook __attribute__((nocommon));
|
||||
struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
|
||||
libc_hidden_data_def (_dl_open_hook);
|
||||
#else
|
||||
static void
|
||||
@ -119,7 +125,7 @@ do_dlsym_private (void *ptr)
|
||||
struct r_found_version vers;
|
||||
vers.name = "GLIBC_PRIVATE";
|
||||
vers.hidden = 1;
|
||||
/* vers.hash = _dl_elf_hash (version); */
|
||||
/* vers.hash = _dl_elf_hash (vers.name); */
|
||||
vers.hash = 0x0963cf85;
|
||||
vers.filename = NULL;
|
||||
|
||||
|
152
elf/dl-load.c
152
elf/dl-load.c
@ -827,6 +827,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
/* Initialize to keep the compiler happy. */
|
||||
const char *errstring = NULL;
|
||||
int errval = 0;
|
||||
struct r_debug *r = _dl_debug_initialize (0);
|
||||
bool make_consistent = false;
|
||||
|
||||
/* Get file information. */
|
||||
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st) < 0, 0))
|
||||
@ -835,6 +837,12 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
call_lose_errno:
|
||||
errval = errno;
|
||||
call_lose:
|
||||
if (make_consistent)
|
||||
{
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
}
|
||||
|
||||
lose (errval, fd, name, realname, l, errstring);
|
||||
}
|
||||
|
||||
@ -905,6 +913,39 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Signal that we are going to add new objects. */
|
||||
if (r->r_state == RT_CONSISTENT)
|
||||
{
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we are going to add new objects. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
|
||||
/* Do not call the functions for any auditing object. */
|
||||
if (head->l_auditing == 0)
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->activity != NULL)
|
||||
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Notify the debugger we have added some objects. We need to
|
||||
call _dl_debug_initialize in a static program in case dynamic
|
||||
linking has not been used before. */
|
||||
r->r_state = RT_ADD;
|
||||
_dl_debug_state ();
|
||||
make_consistent = true;
|
||||
}
|
||||
else
|
||||
assert (r->r_state == RT_ADD);
|
||||
|
||||
/* Enter the new object in the list of loaded objects. */
|
||||
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
||||
if (__builtin_expect (l == NULL, 0))
|
||||
@ -1044,7 +1085,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
|
||||
}
|
||||
|
||||
# ifdef SHARED
|
||||
if (l->l_prev == NULL)
|
||||
if (l->l_prev == NULL || (mode && __RTLD_AUDIT) != 0)
|
||||
/* We are loading the executable itself when the dynamic linker
|
||||
was executed directly. The setup will happen later. */
|
||||
break;
|
||||
@ -1424,6 +1465,26 @@ cannot enable executable stack as shared object requires");
|
||||
add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
|
||||
+ l->l_info[DT_SONAME]->d_un.d_val));
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have a new object. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->objopen != NULL)
|
||||
{
|
||||
l->l_audit[cnt].bindflags
|
||||
= afct->objopen (l, nsid, &l->l_audit[cnt].cookie);
|
||||
|
||||
l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0;
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -1471,7 +1532,8 @@ print_search_path (struct r_search_path_elem **list,
|
||||
this could mean there is something wrong in the installation and the
|
||||
user might want to know about this. */
|
||||
static int
|
||||
open_verify (const char *name, struct filebuf *fbp)
|
||||
open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
|
||||
int whatcode)
|
||||
{
|
||||
/* This is the expected ELF header. */
|
||||
#define ELF32_CLASS ELFCLASS32
|
||||
@ -1500,13 +1562,34 @@ open_verify (const char *name, struct filebuf *fbp)
|
||||
ElfW(Word) type;
|
||||
char vendor[4];
|
||||
} expected_note = { 4, 16, 1, "GNU" };
|
||||
int fd;
|
||||
/* Initialize it to make the compiler happy. */
|
||||
const char *errstring = NULL;
|
||||
int errval = 0;
|
||||
|
||||
#ifdef SHARED
|
||||
/* Give the auditing libraries a chance. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0) && whatcode != 0
|
||||
&& loader->l_auditing == 0)
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->objsearch != NULL)
|
||||
{
|
||||
name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
|
||||
whatcode);
|
||||
if (name == NULL)
|
||||
/* Ignore the path. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Open the file. We always open files read-only. */
|
||||
fd = __open (name, O_RDONLY);
|
||||
int fd = __open (name, O_RDONLY);
|
||||
if (fd != -1)
|
||||
{
|
||||
ElfW(Ehdr) *ehdr;
|
||||
@ -1664,7 +1747,7 @@ open_verify (const char *name, struct filebuf *fbp)
|
||||
static int
|
||||
open_path (const char *name, size_t namelen, int preloaded,
|
||||
struct r_search_path_struct *sps, char **realname,
|
||||
struct filebuf *fbp)
|
||||
struct filebuf *fbp, struct link_map *loader, int whatcode)
|
||||
{
|
||||
struct r_search_path_elem **dirs = sps->dirs;
|
||||
char *buf;
|
||||
@ -1708,12 +1791,16 @@ open_path (const char *name, size_t namelen, int preloaded,
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
||||
_dl_debug_printf (" trying file=%s\n", buf);
|
||||
|
||||
fd = open_verify (buf, fbp);
|
||||
fd = open_verify (buf, fbp, loader, whatcode);
|
||||
if (this_dir->status[cnt] == unknown)
|
||||
{
|
||||
if (fd != -1)
|
||||
this_dir->status[cnt] = existing;
|
||||
else
|
||||
/* Do not update the directory information when loading
|
||||
auditing code. We must try to disturb the program as
|
||||
little as possible. */
|
||||
else if (loader == NULL
|
||||
|| GL(dl_ns)[loader->l_ns]._ns_loaded->l_audit == 0)
|
||||
{
|
||||
/* We failed to open machine dependent library. Let's
|
||||
test whether there is any directory at all. */
|
||||
@ -1731,7 +1818,7 @@ open_path (const char *name, size_t namelen, int preloaded,
|
||||
}
|
||||
|
||||
/* Remember whether we found any existing directory. */
|
||||
here_any |= this_dir->status[cnt] == existing;
|
||||
here_any |= this_dir->status[cnt] != nonexisting;
|
||||
|
||||
if (fd != -1 && __builtin_expect (preloaded, 0)
|
||||
&& INTUSE(__libc_enable_secure))
|
||||
@ -1847,6 +1934,32 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
loader->l_name[0]
|
||||
? loader->l_name : rtld_progname, loader->l_ns);
|
||||
|
||||
#ifdef SHARED
|
||||
/* Give the auditing libraries a chance to change the name before we
|
||||
try anything. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0)
|
||||
&& (loader == NULL || loader->l_auditing == 0))
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->objsearch != NULL)
|
||||
{
|
||||
name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
|
||||
LA_SER_ORIG);
|
||||
if (name == NULL)
|
||||
{
|
||||
/* Do not try anything further. */
|
||||
fd = -1;
|
||||
goto no_file;
|
||||
}
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strchr (name, '/') == NULL)
|
||||
{
|
||||
/* Search for NAME in several places. */
|
||||
@ -1867,7 +1980,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
for (l = loader; fd == -1 && l; l = l->l_loader)
|
||||
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
|
||||
&realname, &fb);
|
||||
&realname, &fb, loader, LA_SER_RUNPATH);
|
||||
|
||||
/* If dynamically linked, try the DT_RPATH of the executable
|
||||
itself. NB: we do this for lookups in any namespace. */
|
||||
@ -1877,21 +1990,24 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
if (l && l->l_type != lt_loaded && l != loader
|
||||
&& cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
|
||||
&realname, &fb);
|
||||
&realname, &fb, loader ?: l, LA_SER_RUNPATH);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the LD_LIBRARY_PATH environment variable. */
|
||||
if (fd == -1 && env_path_list.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, preloaded, &env_path_list,
|
||||
&realname, &fb);
|
||||
&realname, &fb,
|
||||
loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
|
||||
LA_SER_LIBPATH);
|
||||
|
||||
/* Look at the RUNPATH information for this binary. */
|
||||
if (fd == -1 && loader != NULL
|
||||
&& cache_rpath (loader, &loader->l_runpath_dirs,
|
||||
DT_RUNPATH, "RUNPATH"))
|
||||
fd = open_path (name, namelen, preloaded,
|
||||
&loader->l_runpath_dirs, &realname, &fb);
|
||||
&loader->l_runpath_dirs, &realname, &fb, loader,
|
||||
LA_SER_RUNPATH);
|
||||
|
||||
if (fd == -1
|
||||
&& (__builtin_expect (! preloaded, 1)
|
||||
@ -1939,7 +2055,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
|
||||
if (cached != NULL)
|
||||
{
|
||||
fd = open_verify (cached, &fb);
|
||||
fd = open_verify (cached,
|
||||
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
|
||||
LA_SER_CONFIG);
|
||||
if (__builtin_expect (fd != -1, 1))
|
||||
{
|
||||
realname = local_strdup (cached);
|
||||
@ -1959,7 +2077,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
|| __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
|
||||
&& rtld_search_dirs.dirs != (void *) -1)
|
||||
fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
|
||||
&realname, &fb);
|
||||
&realname, &fb, l, LA_SER_DEFAULT);
|
||||
|
||||
/* Add another newline when we are tracing the library loading. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
||||
@ -1975,12 +2093,16 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
||||
fd = -1;
|
||||
else
|
||||
{
|
||||
fd = open_verify (realname, &fb);
|
||||
fd = open_verify (realname, &fb,
|
||||
loader ?: GL(dl_ns)[nsid]._ns_loaded, 0);
|
||||
if (__builtin_expect (fd, 0) == -1)
|
||||
free (realname);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
no_file:
|
||||
#endif
|
||||
/* In case the LOADER information has only been provided to get to
|
||||
the appropriate RUNPATH/RPATH information we do not need it
|
||||
anymore. */
|
||||
|
@ -39,14 +39,24 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
size_t libname_len = strlen (libname) + 1;
|
||||
struct link_map *new;
|
||||
struct libname_list *newname;
|
||||
#ifdef SHARED
|
||||
/* We create the map for the executable before we know whether we have
|
||||
auditing libraries and if yes, how many. Assume the worst. */
|
||||
unsigned int naudit = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC)
|
||||
? DL_NNS : 0);
|
||||
size_t audit_space = naudit * sizeof (new->l_audit[0]);
|
||||
#else
|
||||
# define audit_space 0
|
||||
#endif
|
||||
|
||||
new = (struct link_map *) calloc (sizeof (*new) + sizeof (*newname)
|
||||
+ libname_len, 1);
|
||||
new = (struct link_map *) calloc (sizeof (*new) + audit_space
|
||||
+ sizeof (*newname) + libname_len, 1);
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
|
||||
new->l_real = new;
|
||||
new->l_libname = newname = (struct libname_list *) (new + 1);
|
||||
new->l_libname = newname = (struct libname_list *) ((char *) (new + 1)
|
||||
+ audit_space);
|
||||
newname->name = (char *) memcpy (newname + 1, libname, libname_len);
|
||||
/* newname->next = NULL; We use calloc therefore not necessary. */
|
||||
newname->dont_free = 1;
|
||||
@ -59,6 +69,14 @@ _dl_new_object (char *realname, const char *libname, int type,
|
||||
#endif
|
||||
new->l_ns = nsid;
|
||||
|
||||
#ifdef SHARED
|
||||
for (unsigned int cnt = 0; cnt < naudit; ++cnt)
|
||||
{
|
||||
new->l_audit[cnt].cookie = (uintptr_t) new;
|
||||
/* new->l_audit[cnt].bindflags = 0; */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* new->l_global = 0; We use calloc therefore not necessary. */
|
||||
|
||||
/* Use the 'l_scope_mem' array by default for the the 'l_scope'
|
||||
|
236
elf/dl-open.c
236
elf/dl-open.c
@ -49,11 +49,6 @@ weak_extern (BP_SYM (_dl_sysdep_start))
|
||||
|
||||
extern int __libc_multiple_libcs; /* Defined in init-first.c. */
|
||||
|
||||
extern int __libc_argc attribute_hidden;
|
||||
extern char **__libc_argv attribute_hidden;
|
||||
|
||||
extern char **__environ;
|
||||
|
||||
/* Undefine the following for debugging. */
|
||||
/* #define SCOPE_DEBUG 1 */
|
||||
#ifdef SCOPE_DEBUG
|
||||
@ -74,6 +69,10 @@ struct dl_open_args
|
||||
struct link_map *map;
|
||||
/* Namespace ID. */
|
||||
Lmid_t nsid;
|
||||
/* Original parameters to the program and the current environment. */
|
||||
int argc;
|
||||
char **argv;
|
||||
char **env;
|
||||
};
|
||||
|
||||
|
||||
@ -115,8 +114,8 @@ add_to_global (struct link_map *new)
|
||||
{
|
||||
GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
|
||||
nomem:
|
||||
GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL,
|
||||
N_("cannot extend global scope"));
|
||||
_dl_signal_error (ENOMEM, new->l_libname->name, NULL,
|
||||
N_("cannot extend global scope"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -171,13 +170,16 @@ dl_open_worker (void *a)
|
||||
int lazy;
|
||||
unsigned int i;
|
||||
#ifdef USE_TLS
|
||||
bool any_tls;
|
||||
bool any_tls = false;
|
||||
#endif
|
||||
struct link_map *call_map = NULL;
|
||||
|
||||
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||
|
||||
/* Check whether _dl_open() has been called from a valid DSO. */
|
||||
if (__check_caller (args->caller_dl_open, allow_libc|allow_libdl) != 0)
|
||||
GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller"));
|
||||
if (__check_caller (args->caller_dl_open,
|
||||
allow_libc|allow_libdl|allow_ldso) != 0)
|
||||
_dl_signal_error (0, "dlopen", NULL, N_("invalid caller"));
|
||||
|
||||
/* Determine the caller's map if necessary. This is needed in case
|
||||
we have a DST, when we don't know the namespace ID we have to put
|
||||
@ -226,10 +228,10 @@ dl_open_worker (void *a)
|
||||
char *new_file;
|
||||
|
||||
/* DSTs must not appear in SUID/SGID programs. */
|
||||
if (__libc_enable_secure)
|
||||
if (INTUSE(__libc_enable_secure))
|
||||
/* This is an error. */
|
||||
GLRO(dl_signal_error) (0, "dlopen", NULL,
|
||||
N_("DST not allowed in SUID/SGID programs"));
|
||||
_dl_signal_error (0, "dlopen", NULL,
|
||||
N_("DST not allowed in SUID/SGID programs"));
|
||||
|
||||
|
||||
/* Determine how much space we need. We have to allocate the
|
||||
@ -244,8 +246,8 @@ dl_open_worker (void *a)
|
||||
|
||||
/* If the substitution failed don't try to load. */
|
||||
if (*new_file == '\0')
|
||||
GLRO(dl_signal_error) (0, "dlopen", NULL,
|
||||
N_("empty dynamic string token substitution"));
|
||||
_dl_signal_error (0, "dlopen", NULL,
|
||||
N_("empty dynamic string token substitution"));
|
||||
|
||||
/* Now we have a new file name. */
|
||||
file = new_file;
|
||||
@ -256,8 +258,8 @@ dl_open_worker (void *a)
|
||||
}
|
||||
|
||||
/* Load the named object. */
|
||||
args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
|
||||
mode | __RTLD_CALLMAP, args->nsid);
|
||||
args->map = new = _dl_map_object (call_map, file, 0, lt_loaded, 0,
|
||||
mode | __RTLD_CALLMAP, args->nsid);
|
||||
|
||||
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
|
||||
set and the object is not already loaded. */
|
||||
@ -279,8 +281,8 @@ dl_open_worker (void *a)
|
||||
{
|
||||
/* Let the user know about the opencount. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
_dl_debug_printf ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
|
||||
/* If the user requested the object to be in the global namespace
|
||||
but it is not so far, add it now. */
|
||||
@ -296,23 +298,50 @@ dl_open_worker (void *a)
|
||||
/* Increment just the reference counter of the object. */
|
||||
++new->l_opencount;
|
||||
|
||||
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load that object's dependencies. */
|
||||
GLRO(dl_map_object_deps) (new, NULL, 0, 0,
|
||||
mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
|
||||
_dl_map_object_deps (new, NULL, 0, 0,
|
||||
mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
|
||||
|
||||
/* So far, so good. Now check the versions. */
|
||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||
if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
|
||||
(void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i]->l_real,
|
||||
0, 0);
|
||||
(void) _dl_check_map_versions (new->l_searchlist.r_list[i]->l_real,
|
||||
0, 0);
|
||||
|
||||
#ifdef SCOPE_DEBUG
|
||||
show_scope (new);
|
||||
#endif
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have added all objects. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct link_map *head = GL(dl_ns)[new->l_ns]._ns_loaded;
|
||||
/* Do not call the functions for any auditing object. */
|
||||
if (head->l_auditing == 0)
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->activity != NULL)
|
||||
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Notify the debugger all new objects are now ready to go. */
|
||||
struct r_debug *r = _dl_debug_initialize (0);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
|
||||
/* Only do lazy relocation if `LD_BIND_NOW' is not set. */
|
||||
lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && GLRO(dl_lazy);
|
||||
|
||||
@ -336,12 +365,12 @@ dl_open_worker (void *a)
|
||||
start the profiling. */
|
||||
struct link_map *old_profile_map = GL(dl_profile_map);
|
||||
|
||||
GLRO(dl_relocate_object) (l, l->l_scope, 1, 1);
|
||||
_dl_relocate_object (l, l->l_scope, 1, 1);
|
||||
|
||||
if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
|
||||
{
|
||||
/* We must prepare the profiling. */
|
||||
GLRO(dl_start_profile) ();
|
||||
_dl_start_profile ();
|
||||
|
||||
/* Prevent unloading the object. */
|
||||
GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
|
||||
@ -349,7 +378,7 @@ dl_open_worker (void *a)
|
||||
}
|
||||
else
|
||||
#endif
|
||||
GLRO(dl_relocate_object) (l, l->l_scope, lazy, 0);
|
||||
_dl_relocate_object (l, l->l_scope, lazy, 0);
|
||||
}
|
||||
|
||||
if (l == new)
|
||||
@ -357,22 +386,6 @@ dl_open_worker (void *a)
|
||||
l = l->l_prev;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* Do static TLS initialization now if it has been delayed because
|
||||
the TLS template might not be fully relocated at _dl_allocate_static_tls
|
||||
time. */
|
||||
for (l = new; l; l = l->l_next)
|
||||
if (l->l_need_tls_init)
|
||||
{
|
||||
l->l_need_tls_init = 0;
|
||||
GL(dl_init_static_tls) (l);
|
||||
}
|
||||
|
||||
/* We normally don't bump the TLS generation counter. There must be
|
||||
actually a need to do this. */
|
||||
any_tls = false;
|
||||
#endif
|
||||
|
||||
/* Increment the open count for all dependencies. If the file is
|
||||
not loaded as a dependency here add the search list of the newly
|
||||
loaded object to the scope. */
|
||||
@ -412,8 +425,8 @@ dl_open_worker (void *a)
|
||||
newp = (struct r_scope_elem **)
|
||||
malloc (new_size * sizeof (struct r_scope_elem *));
|
||||
if (newp == NULL)
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
_dl_signal_error (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
imap->l_scope = memcpy (newp, imap->l_scope,
|
||||
cnt * sizeof (imap->l_scope[0]));
|
||||
}
|
||||
@ -423,8 +436,8 @@ dl_open_worker (void *a)
|
||||
realloc (imap->l_scope,
|
||||
new_size * sizeof (struct r_scope_elem *));
|
||||
if (newp == NULL)
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
_dl_signal_error (ENOMEM, "dlopen", NULL,
|
||||
N_("cannot create scope list"));
|
||||
imap->l_scope = newp;
|
||||
}
|
||||
|
||||
@ -441,76 +454,35 @@ dl_open_worker (void *a)
|
||||
> 0, 0))
|
||||
{
|
||||
/* Now that we know the object is loaded successfully add
|
||||
modules containing TLS data to the dtv info table. We
|
||||
modules containing TLS data to the slot info table. We
|
||||
might have to increase its size. */
|
||||
struct dtv_slotinfo_list *listp;
|
||||
struct dtv_slotinfo_list *prevp;
|
||||
size_t idx = new->l_searchlist.r_list[i]->l_tls_modid;
|
||||
_dl_add_to_slotinfo (new->l_searchlist.r_list[i]);
|
||||
|
||||
assert (new->l_searchlist.r_list[i]->l_type == lt_loaded);
|
||||
|
||||
/* Find the place in the dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
prevp = NULL; /* Needed to shut up gcc. */
|
||||
do
|
||||
if (new->l_searchlist.r_list[i]->l_need_tls_init)
|
||||
{
|
||||
/* Does it fit in the array of this list element? */
|
||||
if (idx < listp->len)
|
||||
break;
|
||||
idx -= listp->len;
|
||||
prevp = listp;
|
||||
listp = listp->next;
|
||||
new->l_searchlist.r_list[i]->l_need_tls_init = 0;
|
||||
# ifdef SHARED
|
||||
/* Update the slot information data for at least the
|
||||
generation of the DSO we are allocating data for. */
|
||||
_dl_update_slotinfo (new->l_searchlist.r_list[i]->l_tls_modid);
|
||||
# endif
|
||||
|
||||
GL(dl_init_static_tls) (new->l_searchlist.r_list[i]);
|
||||
assert (new->l_searchlist.r_list[i]->l_need_tls_init == 0);
|
||||
}
|
||||
while (listp != NULL);
|
||||
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* When we come here it means we have to add a new element
|
||||
to the slotinfo list. And the new module must be in
|
||||
the first slot. */
|
||||
assert (idx == 0);
|
||||
|
||||
listp = prevp->next = (struct dtv_slotinfo_list *)
|
||||
malloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* We ran out of memory. We will simply fail this
|
||||
call but don't undo anything we did so far. The
|
||||
application will crash or be terminated anyway very
|
||||
soon. */
|
||||
|
||||
/* We have to do this since some entries in the dtv
|
||||
slotinfo array might already point to this
|
||||
generation. */
|
||||
++GL(dl_tls_generation);
|
||||
|
||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL, N_("\
|
||||
cannot create TLS data structures"));
|
||||
}
|
||||
|
||||
listp->len = TLS_SLOTINFO_SURPLUS;
|
||||
listp->next = NULL;
|
||||
memset (listp->slotinfo, '\0',
|
||||
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
}
|
||||
|
||||
/* Add the information into the slotinfo data structure. */
|
||||
listp->slotinfo[idx].map = new->l_searchlist.r_list[i];
|
||||
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
|
||||
/* We have to bump the generation counter. */
|
||||
any_tls = true;
|
||||
}
|
||||
|
||||
/* Bump the generation number if necessary. */
|
||||
if (any_tls)
|
||||
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
__libc_fatal (_("TLS generation counter wrapped! Please report this."));
|
||||
if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||
_dl_fatal_printf (N_("\
|
||||
TLS generation counter wrapped! Please report this."));
|
||||
#endif
|
||||
|
||||
/* Run the initializer functions of new objects. */
|
||||
GLRO(dl_init) (new, __libc_argc, __libc_argv, __environ);
|
||||
_dl_init (new, args->argc, args->argv, args->env);
|
||||
|
||||
/* Now we can make the new map available in the global scope. */
|
||||
if (mode & RTLD_GLOBAL)
|
||||
@ -532,14 +504,14 @@ cannot create TLS data structures"));
|
||||
|
||||
/* Let the user know about the opencount. */
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
_dl_debug_printf ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_opencount);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
internal_function
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
|
||||
_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
|
||||
int argc, char *argv[], char *env[])
|
||||
{
|
||||
struct dl_open_args args;
|
||||
const char *objname;
|
||||
@ -548,12 +520,13 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
|
||||
|
||||
if ((mode & RTLD_BINDING_MASK) == 0)
|
||||
/* One of the flags must be set. */
|
||||
GLRO(dl_signal_error) (EINVAL, file, NULL,
|
||||
N_("invalid mode for dlopen()"));
|
||||
_dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));
|
||||
|
||||
/* Make sure we are alone. */
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
|
||||
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||
|
||||
if (nsid == LM_ID_NEWLM)
|
||||
{
|
||||
/* Find a new namespace. */
|
||||
@ -566,16 +539,18 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
|
||||
/* No more namespace available. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
|
||||
GLRO(dl_signal_error) (EINVAL, file, NULL, N_("\
|
||||
_dl_signal_error (EINVAL, file, NULL, N_("\
|
||||
no more namespaces available for dlmopen()"));
|
||||
}
|
||||
}
|
||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||
direct placements is only causing problems. */
|
||||
direct placements is only causing problems. Also don't allow
|
||||
loading into a namespace used for auditing. */
|
||||
else if (nsid != LM_ID_BASE && nsid != __LM_ID_CALLER
|
||||
&& GL(dl_ns)[nsid]._ns_nloaded == 0)
|
||||
GLRO(dl_signal_error) (EINVAL, file, NULL,
|
||||
N_("invalid target namespace in dlmopen()"));
|
||||
&& (GL(dl_ns)[nsid]._ns_nloaded == 0
|
||||
|| GL(dl_ns)[nsid]._ns_loaded->l_auditing))
|
||||
_dl_signal_error (EINVAL, file, NULL,
|
||||
N_("invalid target namespace in dlmopen()"));
|
||||
|
||||
args.file = file;
|
||||
args.mode = mode;
|
||||
@ -583,11 +558,14 @@ no more namespaces available for dlmopen()"));
|
||||
args.caller_dl_open = RETURN_ADDRESS (0);
|
||||
args.map = NULL;
|
||||
args.nsid = nsid;
|
||||
errcode = GLRO(dl_catch_error) (&objname, &errstring, dl_open_worker, &args);
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
args.env = env;
|
||||
errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args);
|
||||
|
||||
#ifndef MAP_COPY
|
||||
/* We must munmap() the cache file. */
|
||||
GLRO(dl_unload_cache) ();
|
||||
_dl_unload_cache ();
|
||||
#endif
|
||||
|
||||
/* Release the lock. */
|
||||
@ -603,21 +581,22 @@ no more namespaces available for dlmopen()"));
|
||||
state if relocation failed, for example. */
|
||||
if (args.map)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Increment open counters for all objects since this
|
||||
sometimes has not happened yet. */
|
||||
if (args.map->l_searchlist.r_list[0]->l_opencount == 0)
|
||||
for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
|
||||
for (unsigned int i = 0; i < args.map->l_searchlist.r_nlist; ++i)
|
||||
++args.map->l_searchlist.r_list[i]->l_opencount;
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* Maybe some of the modules which were loaded uses TLS.
|
||||
/* Maybe some of the modules which were loaded use TLS.
|
||||
Since it will be removed in the following _dl_close call
|
||||
we have to mark the dtv array as having gaps to fill
|
||||
the holes. This is a pessimistic assumption which won't
|
||||
hurt if not true. */
|
||||
GL(dl_tls_dtv_gaps) = true;
|
||||
we have to mark the dtv array as having gaps to fill the
|
||||
holes. This is a pessimistic assumption which won't hurt
|
||||
if not true. There is no need to do this when we are
|
||||
loading the auditing DSOs since TLS has not yet been set
|
||||
up. */
|
||||
if ((mode & __RTLD_AUDIT) == 0)
|
||||
GL(dl_tls_dtv_gaps) = true;
|
||||
#endif
|
||||
|
||||
_dl_close (args.map);
|
||||
@ -639,20 +618,23 @@ no more namespaces available for dlmopen()"));
|
||||
memcpy (local_errstring, errstring, len_errstring);
|
||||
}
|
||||
|
||||
if (errstring != _dl_out_of_memory)
|
||||
if (errstring != INTUSE(_dl_out_of_memory))
|
||||
free ((char *) errstring);
|
||||
|
||||
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||
|
||||
/* Reraise the error. */
|
||||
GLRO(dl_signal_error) (errcode, objname, NULL, local_errstring);
|
||||
_dl_signal_error (errcode, objname, NULL, local_errstring);
|
||||
}
|
||||
|
||||
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||
|
||||
#ifndef SHARED
|
||||
DL_STATIC_INIT (args.map);
|
||||
#endif
|
||||
|
||||
return args.map;
|
||||
}
|
||||
libc_hidden_def (_dl_open)
|
||||
|
||||
|
||||
#ifdef SCOPE_DEBUG
|
||||
|
@ -48,8 +48,6 @@ void
|
||||
internal_function __attribute_noinline__
|
||||
_dl_allocate_static_tls (struct link_map *map)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
/* If the alignment requirements are too high fail. */
|
||||
if (map->l_tls_align > GL(dl_tls_static_align))
|
||||
{
|
||||
@ -71,15 +69,15 @@ cannot allocate memory in static TLS block"));
|
||||
|
||||
n = (freebytes - blsize) / map->l_tls_align;
|
||||
|
||||
offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
|
||||
- map->l_tls_firstbyte_offset);
|
||||
size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
|
||||
- map->l_tls_firstbyte_offset);
|
||||
|
||||
map->l_tls_offset = GL(dl_tls_static_used) = offset;
|
||||
# elif TLS_DTV_AT_TP
|
||||
size_t used;
|
||||
size_t check;
|
||||
|
||||
offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
|
||||
size_t offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
|
||||
used = offset + map->l_tls_blocksize;
|
||||
check = used;
|
||||
/* dl_tls_static_used includes the TCB at the beginning. */
|
||||
@ -93,8 +91,20 @@ cannot allocate memory in static TLS block"));
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
# endif
|
||||
|
||||
if (map->l_relocated)
|
||||
GL(dl_init_static_tls) (map);
|
||||
/* If the object is not yet relocated we cannot initialize the
|
||||
static TLS region. Delay it. */
|
||||
if (map->l_real->l_relocated)
|
||||
{
|
||||
#ifdef SHARED
|
||||
if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
|
||||
0))
|
||||
/* Update the slot information data for at least the generation of
|
||||
the DSO we are allocating data for. */
|
||||
(void) _dl_update_slotinfo (map->l_tls_modid);
|
||||
#endif
|
||||
|
||||
GL(dl_init_static_tls) (map);
|
||||
}
|
||||
else
|
||||
map->l_need_tls_init = 1;
|
||||
}
|
||||
@ -114,7 +124,8 @@ _dl_nothread_init_static_tls (struct link_map *map)
|
||||
# endif
|
||||
|
||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
||||
THREAD_DTV ()[map->l_tls_modid].pointer = dest;
|
||||
THREAD_DTV ()[map->l_tls_modid].pointer.val = dest;
|
||||
THREAD_DTV ()[map->l_tls_modid].pointer.is_static = true;
|
||||
|
||||
/* Initialize the memory. */
|
||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
@ -137,11 +148,17 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
/* Initialize it to make the compiler happy. */
|
||||
const char *errstring = NULL;
|
||||
|
||||
#ifdef SHARED
|
||||
/* If we are auditing, install the same handlers we need for profiling. */
|
||||
consider_profiling |= GLRO(dl_audit) != NULL;
|
||||
#endif
|
||||
|
||||
if (l->l_relocated)
|
||||
return;
|
||||
|
||||
/* If DT_BIND_NOW is set relocate all references in this object. We
|
||||
do not do this if we are profiling, of course. */
|
||||
// XXX Correct for auditing?
|
||||
if (!consider_profiling
|
||||
&& __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
|
||||
lazy = 0;
|
||||
@ -225,29 +242,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
l->l_lookup_cache.ret = (*ref); \
|
||||
l->l_lookup_cache.value = _lr; })) \
|
||||
: l)
|
||||
#define RESOLVE(ref, version, r_type) \
|
||||
(ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \
|
||||
? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \
|
||||
&& elf_machine_type_class (r_type) == l->l_lookup_cache.type_class) \
|
||||
? (bump_num_cache_relocations (), \
|
||||
(*ref) = l->l_lookup_cache.ret, \
|
||||
l->l_lookup_cache.value) \
|
||||
: ({ lookup_t _lr; \
|
||||
int _tc = elf_machine_type_class (r_type); \
|
||||
l->l_lookup_cache.type_class = _tc; \
|
||||
l->l_lookup_cache.sym = (*ref); \
|
||||
const struct r_found_version *v = NULL; \
|
||||
int flags = DL_LOOKUP_ADD_DEPENDENCY; \
|
||||
if ((version) != NULL && (version)->hash != 0) \
|
||||
{ \
|
||||
v = (version); \
|
||||
flags = 0; \
|
||||
} \
|
||||
_lr = _dl_lookup_symbol_x (strtab + (*ref)->st_name, l, (ref), \
|
||||
scope, v, _tc, flags, NULL); \
|
||||
l->l_lookup_cache.ret = (*ref); \
|
||||
l->l_lookup_cache.value = _lr; })) \
|
||||
: l->l_addr)
|
||||
|
||||
/* This macro is used as a callback from elf_machine_rel{a,} when a
|
||||
static TLS reloc is about to be performed. Since (in dl-load.c) we
|
||||
@ -276,20 +270,19 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
will be NULL. */
|
||||
if (l->l_info[DT_PLTRELSZ] == NULL)
|
||||
{
|
||||
errstring = N_("%s: profiler found no PLTREL in object %s\n");
|
||||
errstring = N_("%s: no PLTREL found in object %s\n");
|
||||
fatal:
|
||||
_dl_fatal_printf (errstring,
|
||||
rtld_progname ?: "<program name unknown>",
|
||||
l->l_name);
|
||||
}
|
||||
|
||||
l->l_reloc_result =
|
||||
(ElfW(Addr) *) calloc (sizeof (ElfW(Addr)),
|
||||
l->l_info[DT_PLTRELSZ]->d_un.d_val);
|
||||
l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
|
||||
l->l_info[DT_PLTRELSZ]->d_un.d_val);
|
||||
if (l->l_reloc_result == NULL)
|
||||
{
|
||||
errstring = N_("\
|
||||
%s: profiler out of memory shadowing PLTREL of %s\n");
|
||||
%s: out of memory to store relocation results for %s\n");
|
||||
goto fatal;
|
||||
}
|
||||
}
|
||||
|
270
elf/dl-runtime.c
270
elf/dl-runtime.c
@ -1,5 +1,5 @@
|
||||
/* On-demand PLT fixup for shared objects.
|
||||
Copyright (C) 1995-2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-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
|
||||
@ -51,15 +51,15 @@
|
||||
function. */
|
||||
|
||||
#ifndef ELF_MACHINE_NO_PLT
|
||||
static ElfW(Addr)
|
||||
__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||
fixup (
|
||||
ElfW(Addr)
|
||||
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||
_dl_fixup (
|
||||
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
||||
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
||||
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
||||
# endif
|
||||
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
||||
without the `__unbounded' qualifier. */
|
||||
struct link_map *__unbounded l, ElfW(Word) reloc_offset)
|
||||
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
||||
without the `__unbounded' qualifier. */
|
||||
struct link_map *__unbounded l, ElfW(Word) reloc_offset)
|
||||
{
|
||||
const ElfW(Sym) *const symtab
|
||||
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
|
||||
@ -80,8 +80,6 @@ fixup (
|
||||
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
||||
{
|
||||
const struct r_found_version *version = NULL;
|
||||
// XXX Why exactly do we have the differentiation of the flags here?
|
||||
int flags = DL_LOOKUP_ADD_DEPENDENCY;
|
||||
|
||||
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||
{
|
||||
@ -91,8 +89,6 @@ fixup (
|
||||
version = &l->l_versions[ndx];
|
||||
if (version->hash == 0)
|
||||
version = NULL;
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
|
||||
@ -109,9 +105,7 @@ fixup (
|
||||
/* We already found the symbol. The module (and therefore its load
|
||||
address) is also known. */
|
||||
value = l->l_addr + sym->st_value;
|
||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
||||
result = l;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* And now perhaps the relocation addend. */
|
||||
@ -127,45 +121,45 @@ fixup (
|
||||
|
||||
#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
|
||||
|
||||
static ElfW(Addr)
|
||||
__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||
profile_fixup (
|
||||
ElfW(Addr)
|
||||
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||
_dl_profile_fixup (
|
||||
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
||||
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
||||
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
||||
#endif
|
||||
struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr)
|
||||
struct link_map *l, ElfW(Word) reloc_offset,
|
||||
ElfW(Addr) retaddr, const void *regs, long int *framesizep)
|
||||
{
|
||||
void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = INTUSE(_dl_mcount);
|
||||
ElfW(Addr) *resultp;
|
||||
lookup_t result;
|
||||
ElfW(Addr) value;
|
||||
|
||||
/* This is the address in the array where we store the result of previous
|
||||
relocations. */
|
||||
resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
|
||||
struct reloc_result *reloc_result
|
||||
= &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
|
||||
ElfW(Addr) *resultp = &reloc_result->addr;
|
||||
|
||||
value = *resultp;
|
||||
ElfW(Addr) value = *resultp;
|
||||
if (value == 0)
|
||||
{
|
||||
/* This is the first time we have to relocate this object. */
|
||||
const ElfW(Sym) *const symtab
|
||||
= (const void *) D_PTR (l, l_info[DT_SYMTAB]);
|
||||
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
|
||||
const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]);
|
||||
|
||||
const PLTREL *const reloc
|
||||
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
|
||||
const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)];
|
||||
const ElfW(Sym) *defsym = refsym;
|
||||
lookup_t result;
|
||||
|
||||
/* Sanity check that we're really looking at a PLT relocation. */
|
||||
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
|
||||
|
||||
/* Look up the target symbol. If the symbol is marked STV_PROTECTED
|
||||
don't look in the global scope. */
|
||||
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
||||
if (__builtin_expect (ELFW(ST_VISIBILITY) (refsym->st_other), 0) == 0)
|
||||
{
|
||||
const struct r_found_version *version = NULL;
|
||||
// XXX Why exactly do we have the differentiation of the flags here?
|
||||
int flags = DL_LOOKUP_ADD_DEPENDENCY;
|
||||
|
||||
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||
{
|
||||
@ -175,11 +169,9 @@ profile_fixup (
|
||||
version = &l->l_versions[ndx];
|
||||
if (version->hash == 0)
|
||||
version = NULL;
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
|
||||
result = _dl_lookup_symbol_x (strtab + refsym->st_name, l, &defsym,
|
||||
l->l_scope, version,
|
||||
ELF_RTYPE_CLASS_PLT,
|
||||
DL_LOOKUP_ADD_DEPENDENCY, NULL);
|
||||
@ -187,25 +179,185 @@ profile_fixup (
|
||||
/* Currently result contains the base load address (or link map)
|
||||
of the object that defines sym. Now add in the symbol
|
||||
offset. */
|
||||
value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
|
||||
value = (defsym != NULL
|
||||
? LOOKUP_VALUE_ADDRESS (result) + defsym->st_value : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We already found the symbol. The module (and therefore its load
|
||||
address) is also known. */
|
||||
value = l->l_addr + sym->st_value;
|
||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
||||
value = l->l_addr + refsym->st_value;
|
||||
result = l;
|
||||
#endif
|
||||
}
|
||||
/* And now perhaps the relocation addend. */
|
||||
value = elf_machine_plt_value (l, reloc, value);
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have a new binding. Provide the
|
||||
auditing libraries the possibility to change the value and
|
||||
tell us whether further auditing is wanted. */
|
||||
if (defsym != NULL && GLRO(dl_naudit) > 0)
|
||||
{
|
||||
reloc_result->bound = result;
|
||||
/* Compute index of the symbol entry in the symbol table of
|
||||
the DSO with the definition. */
|
||||
reloc_result->boundndx = (defsym
|
||||
- (ElfW(Sym) *) D_PTR (result,
|
||||
l_info[DT_SYMTAB]));
|
||||
|
||||
/* Determine whether any of the two participating DSOs is
|
||||
interested in auditing. */
|
||||
if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0)
|
||||
{
|
||||
unsigned int altvalue = 0;
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
/* Synthesize a symbol record where the st_value field is
|
||||
the result. */
|
||||
ElfW(Sym) sym = *defsym;
|
||||
sym.st_value = value;
|
||||
|
||||
/* Keep track whether there is any interest in tracing
|
||||
the call in the lower two bits. */
|
||||
assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8);
|
||||
assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3);
|
||||
reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT;
|
||||
|
||||
const char *strtab2 = (const void *) D_PTR (result,
|
||||
l_info[DT_STRTAB]);
|
||||
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
/* XXX Check whether both DSOs must request action or
|
||||
only one */
|
||||
if ((l->l_audit[cnt].bindflags & LA_FLG_BINDFROM) != 0
|
||||
&& (result->l_audit[cnt].bindflags & LA_FLG_BINDTO) != 0)
|
||||
{
|
||||
unsigned int flags = altvalue;
|
||||
if (afct->symbind != NULL)
|
||||
{
|
||||
uintptr_t new_value
|
||||
= afct->symbind (&sym, reloc_result->boundndx,
|
||||
&l->l_audit[cnt].cookie,
|
||||
&result->l_audit[cnt].cookie,
|
||||
&flags,
|
||||
strtab2 + defsym->st_name);
|
||||
if (new_value != (uintptr_t) sym.st_value)
|
||||
{
|
||||
altvalue = LA_SYMB_ALTVALUE;
|
||||
sym.st_value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember the results for every audit library and
|
||||
store a summary in the first two bits. */
|
||||
reloc_result->enterexit
|
||||
&= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT);
|
||||
reloc_result->enterexit
|
||||
|= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
|
||||
<< ((cnt + 1) * 2));
|
||||
}
|
||||
else
|
||||
/* If the bind flags say this auditor is not interested,
|
||||
set the bits manually. */
|
||||
reloc_result->enterexit
|
||||
|= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)
|
||||
<< ((cnt + 1) * 2));
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
|
||||
reloc_result->flags = altvalue;
|
||||
value = sym.st_value;
|
||||
}
|
||||
else
|
||||
/* Set all bits since this symbol binding is not interesting. */
|
||||
reloc_result->enterexit = (1u << DL_NNS) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Store the result for later runs. */
|
||||
if (__builtin_expect (! GLRO(dl_bind_not), 1))
|
||||
*resultp = value;
|
||||
}
|
||||
|
||||
/* By default we do not call the pltexit function. */
|
||||
long int framesize = -1;
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: report the PLT entering and allow the
|
||||
auditors to change the value. */
|
||||
if (value != 0 && GLRO(dl_naudit) > 0
|
||||
/* Don't do anything if no auditor wants to intercept this call. */
|
||||
&& (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0)
|
||||
{
|
||||
ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
|
||||
l_info[DT_SYMTAB])
|
||||
+ reloc_result->boundndx);
|
||||
|
||||
/* Set up the sym parameter. */
|
||||
ElfW(Sym) sym = *defsym;
|
||||
sym.st_value = value;
|
||||
|
||||
/* Get the symbol name. */
|
||||
const char *strtab = (const void *) D_PTR (reloc_result->bound,
|
||||
l_info[DT_STRTAB]);
|
||||
const char *symname = strtab + sym.st_name;
|
||||
|
||||
/* Keep track of overwritten addresses. */
|
||||
unsigned int altvalue = reloc_result->flags;
|
||||
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->ARCH_LA_PLTENTER != NULL
|
||||
&& (reloc_result->enterexit
|
||||
& (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0)
|
||||
{
|
||||
unsigned int flags = altvalue;
|
||||
long int new_framesize = -1;
|
||||
uintptr_t new_value
|
||||
= afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx,
|
||||
&l->l_audit[cnt].cookie,
|
||||
&reloc_result->bound->l_audit[cnt].cookie,
|
||||
regs, &flags, symname,
|
||||
&new_framesize);
|
||||
if (new_value != (uintptr_t) sym.st_value)
|
||||
{
|
||||
altvalue = LA_SYMB_ALTVALUE;
|
||||
sym.st_value = new_value;
|
||||
}
|
||||
|
||||
/* Remember the results for every audit library and
|
||||
store a summary in the first two bits. */
|
||||
reloc_result->enterexit
|
||||
|= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT))
|
||||
<< (2 * (cnt + 1)));
|
||||
|
||||
if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT
|
||||
<< (2 * (cnt + 1))))
|
||||
== 0 && new_framesize != -1 && framesize != -2)
|
||||
{
|
||||
/* If this is the first call providing information,
|
||||
use it. */
|
||||
if (framesize == -1)
|
||||
framesize = new_framesize;
|
||||
/* If two pltenter calls provide conflicting information,
|
||||
use the larger value. */
|
||||
else if (new_framesize != framesize)
|
||||
framesize = MAX (new_framesize, framesize);
|
||||
}
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
|
||||
value = sym.st_value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Store the frame size information. */
|
||||
*framesizep = framesize;
|
||||
|
||||
(*mcount_fct) (retaddr, value);
|
||||
|
||||
return value;
|
||||
@ -214,9 +366,45 @@ profile_fixup (
|
||||
#endif /* PROF && ELF_MACHINE_NO_PLT */
|
||||
|
||||
|
||||
/* This macro is defined in dl-machine.h to define the entry point called
|
||||
by the PLT. The `fixup' function above does the real work, but a little
|
||||
more twiddling is needed to get the stack right and jump to the address
|
||||
finally resolved. */
|
||||
#include <stdio.h>
|
||||
void
|
||||
ARCH_FIXUP_ATTRIBUTE
|
||||
_dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_offset,
|
||||
const void *inregs, void *outregs)
|
||||
{
|
||||
#ifdef SHARED
|
||||
/* This is the address in the array where we store the result of previous
|
||||
relocations. */
|
||||
// XXX Maybe the bound information must be stored on the stack since
|
||||
// XXX with bind_not a new value could have been stored in the meantime.
|
||||
struct reloc_result *reloc_result
|
||||
= &l->l_reloc_result[reloc_offset / sizeof (PLTREL)];
|
||||
ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
|
||||
l_info[DT_SYMTAB])
|
||||
+ reloc_result->boundndx);
|
||||
|
||||
ELF_MACHINE_RUNTIME_TRAMPOLINE
|
||||
/* Set up the sym parameter. */
|
||||
ElfW(Sym) sym = *defsym;
|
||||
|
||||
/* Get the symbol name. */
|
||||
const char *strtab = (const void *) D_PTR (reloc_result->bound,
|
||||
l_info[DT_STRTAB]);
|
||||
const char *symname = strtab + sym.st_name;
|
||||
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->ARCH_LA_PLTEXIT != NULL
|
||||
&& (reloc_result->enterexit
|
||||
& (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0)
|
||||
{
|
||||
afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx,
|
||||
&l->l_audit[cnt].cookie,
|
||||
&reloc_result->bound->l_audit[cnt].cookie,
|
||||
inregs, outregs, symname);
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
59
elf/dl-sym.c
59
elf/dl-sym.c
@ -116,14 +116,69 @@ RTLD_NEXT used in code not dynamically loaded"));
|
||||
|
||||
if (ref != NULL)
|
||||
{
|
||||
void *value;
|
||||
|
||||
#if defined USE_TLS && defined SHARED
|
||||
if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
|
||||
/* The found symbol is a thread-local storage variable.
|
||||
Return the address for to the current thread. */
|
||||
return _dl_tls_symaddr (result, ref);
|
||||
value = _dl_tls_symaddr (result, ref);
|
||||
else
|
||||
#endif
|
||||
value = DL_SYMBOL_ADDRESS (result, ref);
|
||||
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have a new binding. Provide the
|
||||
auditing libraries the possibility to change the value and
|
||||
tell us whether further auditing is wanted. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
const char *strtab = (const char *) D_PTR (result,
|
||||
l_info[DT_STRTAB]);
|
||||
/* Compute index of the symbol entry in the symbol table of
|
||||
the DSO with the definition. */
|
||||
unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
|
||||
l_info[DT_SYMTAB]));
|
||||
|
||||
if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
|
||||
{
|
||||
unsigned int altvalue = 0;
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
/* Synthesize a symbol record where the st_value field is
|
||||
the result. */
|
||||
ElfW(Sym) sym = *ref;
|
||||
sym.st_value = (ElfW(Addr)) value;
|
||||
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->symbind != NULL
|
||||
&& ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
|
||||
!= 0
|
||||
|| ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
|
||||
!= 0)))
|
||||
{
|
||||
unsigned int flags = altvalue | LA_SYMB_DLSYM;
|
||||
uintptr_t new_value
|
||||
= afct->symbind (&sym, ndx,
|
||||
&match->l_audit[cnt].cookie,
|
||||
&result->l_audit[cnt].cookie,
|
||||
&flags, strtab + ref->st_name);
|
||||
if (new_value != (uintptr_t) sym.st_value)
|
||||
{
|
||||
altvalue = LA_SYMB_ALTVALUE;
|
||||
sym.st_value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
|
||||
value = (void *) sym.st_value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return DL_SYMBOL_ADDRESS (result, ref);
|
||||
return value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <elf.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef RESOLVE
|
||||
#ifdef RESOLVE_MAP
|
||||
/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
|
||||
ElfW(Addr), because not all architectures can assume that the
|
||||
relocated address is properly aligned, whereas the compiler is
|
||||
@ -64,7 +64,7 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
|
||||
|
||||
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
|
||||
#ifndef RESOLVE
|
||||
#ifndef RESOLVE_MAP
|
||||
static
|
||||
#else
|
||||
auto
|
||||
@ -199,7 +199,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef RESOLVE
|
||||
#ifdef RESOLVE_MAP
|
||||
|
||||
# ifdef RTLD_BOOTSTRAP
|
||||
# define ELF_DURING_STARTUP (1)
|
||||
|
69
elf/link.h
69
elf/link.h
@ -1,6 +1,6 @@
|
||||
/* Data structure for communication from the run-time dynamic linker for
|
||||
loaded ELF shared objects.
|
||||
Copyright (C) 1995-1999, 2000, 2001, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-2001, 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
|
||||
@ -33,6 +33,7 @@
|
||||
#define _ElfW_1(e,w,t) e##w##t
|
||||
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
|
||||
/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||
details of shared object loading to the debugger. If the executable's
|
||||
@ -94,6 +95,47 @@ struct link_map
|
||||
|
||||
#ifdef __USE_GNU
|
||||
|
||||
/* Version numbers for la_version handshake interface. */
|
||||
#define LAV_CURRENT 1
|
||||
|
||||
/* Activity types signaled through la_activity. */
|
||||
enum
|
||||
{
|
||||
LA_ACT_CONSISTENT, /* Link map consistent again. */
|
||||
LA_ACT_ADD, /* New object will be added. */
|
||||
LA_ACT_DELETE /* Objects will be removed. */
|
||||
};
|
||||
|
||||
/* Values representing origin of name for dynamic loading. */
|
||||
enum
|
||||
{
|
||||
LA_SER_ORIG = 0x01, /* Original name. */
|
||||
LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */
|
||||
LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */
|
||||
LA_SER_CONFIG = 0x08, /* Found through ldconfig. */
|
||||
LA_SER_DEFAULT = 0x40, /* Default directory. */
|
||||
LA_SER_SECURE = 0x80 /* Unused. */
|
||||
};
|
||||
|
||||
/* Values for la_objopen return value. */
|
||||
enum
|
||||
{
|
||||
LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */
|
||||
LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */
|
||||
};
|
||||
|
||||
/* Values for la_symbind flags parameter. */
|
||||
enum
|
||||
{
|
||||
LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */
|
||||
LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */
|
||||
LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */
|
||||
LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */
|
||||
LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous
|
||||
la_symbind call. */
|
||||
};
|
||||
|
||||
|
||||
struct dl_phdr_info
|
||||
{
|
||||
ElfW(Addr) dlpi_addr;
|
||||
@ -114,9 +156,28 @@ struct dl_phdr_info
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern int dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
|
||||
size_t size, void *data),
|
||||
void *data);
|
||||
extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
|
||||
size_t, void *),
|
||||
void *__data);
|
||||
|
||||
|
||||
/* Prototypes for the ld.so auditing interfaces. These are not
|
||||
defined anywhere in ld.so but instead have to be provided by the
|
||||
auditing DSO. */
|
||||
extern unsigned int la_version (unsigned int __version);
|
||||
extern void la_activity (uintptr_t *__cookie, unsigned int __flag);
|
||||
extern char *la_objsearch (const char *__name, uintptr_t *__cookie,
|
||||
unsigned int __flag);
|
||||
extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid,
|
||||
uintptr_t *__cookie);
|
||||
extern void la_preinit (uintptr_t *__cookie);
|
||||
extern uintptr_t la_symbind32 (Elf32_Sym *__sym, unsigned int __ndx,
|
||||
uintptr_t *__refcook, uintptr_t *__defcook,
|
||||
unsigned int *__flags, const char *__symname);
|
||||
extern uintptr_t la_symbind64 (Elf64_Sym *__sym, unsigned int __ndx,
|
||||
uintptr_t *__refcook, uintptr_t *__defcook,
|
||||
unsigned int *__flags, const char *__symname);
|
||||
extern unsigned int la_objclose (uintptr_t *__cookie);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
541
elf/rtld.c
541
elf/rtld.c
@ -79,6 +79,13 @@ INTDEF(_dl_argv)
|
||||
/* Nonzero if we were run directly. */
|
||||
unsigned int _dl_skip_args attribute_relro attribute_hidden;
|
||||
|
||||
/* List of auditing DSOs. */
|
||||
static struct audit_list
|
||||
{
|
||||
const char *name;
|
||||
struct audit_list *next;
|
||||
} *audit_list;
|
||||
|
||||
#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Set nonzero during loading and initialization of executable and
|
||||
libraries, cleared before the executable's entry point runs. This
|
||||
@ -126,25 +133,14 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
|
||||
._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
|
||||
._dl_check_caller = _dl_check_caller,
|
||||
._dl_open = _dl_open,
|
||||
._dl_close = _dl_close
|
||||
};
|
||||
/* If we would use strong_alias here the compiler would see a
|
||||
non-hidden definition. This would undo the effect of the previous
|
||||
@ -472,7 +468,7 @@ _dl_start (void *arg)
|
||||
while (remaining-- > 0)
|
||||
*p++ = '\0';
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
/* Install the pointer to the dtv. */
|
||||
|
||||
@ -514,6 +510,7 @@ _dl_start (void *arg)
|
||||
data access using the global offset table. */
|
||||
|
||||
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
|
||||
bootstrap_map.l_relocated = 1;
|
||||
}
|
||||
|
||||
/* Please note that we don't allow profiling of this object and
|
||||
@ -566,6 +563,19 @@ struct map_args
|
||||
struct link_map *map;
|
||||
};
|
||||
|
||||
struct dlmopen_args
|
||||
{
|
||||
const char *fname;
|
||||
struct link_map *map;
|
||||
};
|
||||
|
||||
struct lookup_args
|
||||
{
|
||||
const char *name;
|
||||
struct link_map *map;
|
||||
void *result;
|
||||
};
|
||||
|
||||
/* Arguments to version_check_doit. */
|
||||
struct version_check_args
|
||||
{
|
||||
@ -590,6 +600,28 @@ map_doit (void *a)
|
||||
LM_ID_BASE);
|
||||
}
|
||||
|
||||
static void
|
||||
dlmopen_doit (void *a)
|
||||
{
|
||||
struct dlmopen_args *args = (struct dlmopen_args *) a;
|
||||
args->map = _dl_open (args->fname, RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT,
|
||||
dl_main, LM_ID_NEWLM, _dl_argc, INTUSE(_dl_argv),
|
||||
__environ);
|
||||
}
|
||||
|
||||
static void
|
||||
lookup_doit (void *a)
|
||||
{
|
||||
struct lookup_args *args = (struct lookup_args *) a;
|
||||
const ElfW(Sym) *ref = NULL;
|
||||
args->result = NULL;
|
||||
lookup_t l = _dl_lookup_symbol_x (args->name, args->map, &ref,
|
||||
args->map->l_local_scope, NULL, 0,
|
||||
DL_LOOKUP_RETURN_NEWEST, NULL);
|
||||
if (ref != NULL)
|
||||
args->result = DL_SYMBOL_ADDRESS (l, ref);
|
||||
}
|
||||
|
||||
static void
|
||||
version_check_doit (void *a)
|
||||
{
|
||||
@ -648,6 +680,80 @@ match_version (const char *string, struct link_map *map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
static bool tls_init_tp_called;
|
||||
|
||||
static void *
|
||||
init_tls (void)
|
||||
{
|
||||
/* Number of elements in the static TLS block. */
|
||||
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
|
||||
|
||||
/* Do not do this twice. The audit interface might have required
|
||||
the DTV interfaces to be set up early. */
|
||||
if (GL(dl_initial_dtv) != NULL)
|
||||
return NULL;
|
||||
|
||||
/* Allocate the array which contains the information about the
|
||||
dtv slots. We allocate a few entries more than needed to
|
||||
avoid the need for reallocation. */
|
||||
size_t nelem = GL(dl_tls_max_dtv_idx) + 1 + TLS_SLOTINFO_SURPLUS;
|
||||
|
||||
/* Allocate. */
|
||||
GL(dl_tls_dtv_slotinfo_list) = (struct dtv_slotinfo_list *)
|
||||
calloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ nelem * sizeof (struct dtv_slotinfo), 1);
|
||||
/* No need to check the return value. If memory allocation failed
|
||||
the program would have been terminated. */
|
||||
|
||||
struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
|
||||
GL(dl_tls_dtv_slotinfo_list)->len = nelem;
|
||||
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
|
||||
|
||||
/* Fill in the information from the loaded modules. No namespace
|
||||
but the base one can be filled at this time. */
|
||||
assert (GL(dl_ns)[LM_ID_BASE + 1]._ns_loaded == NULL);
|
||||
int i = 0;
|
||||
for (struct link_map *l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL;
|
||||
l = l->l_next)
|
||||
if (l->l_tls_blocksize != 0)
|
||||
{
|
||||
/* This is a module with TLS data. Store the map reference.
|
||||
The generation counter is zero. */
|
||||
slotinfo[i].map = l;
|
||||
/* slotinfo[i].gen = 0; */
|
||||
++i;
|
||||
}
|
||||
assert (i == GL(dl_tls_max_dtv_idx));
|
||||
|
||||
/* Compute the TLS offsets for the various blocks. */
|
||||
_dl_determine_tlsoffset ();
|
||||
|
||||
/* Construct the static TLS block and the dtv for the initial
|
||||
thread. For some platforms this will include allocating memory
|
||||
for the thread descriptor. The memory for the TLS block will
|
||||
never be freed. It should be allocated accordingly. The dtv
|
||||
array can be changed if dynamic loading requires it. */
|
||||
void *tcbp = _dl_allocate_tls_storage ();
|
||||
if (tcbp == NULL)
|
||||
_dl_fatal_printf ("\
|
||||
cannot allocate TLS data structures for initial thread");
|
||||
|
||||
/* Store for detection of the special case by __tls_get_addr
|
||||
so it knows not to pass this dtv to the normal realloc. */
|
||||
GL(dl_initial_dtv) = GET_DTV (tcbp);
|
||||
|
||||
/* And finally install it for the main thread. If ld.so itself uses
|
||||
TLS we know the thread pointer was initialized earlier. */
|
||||
const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
|
||||
if (__builtin_expect (lossage != NULL, 0))
|
||||
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
|
||||
tls_init_tp_called = true;
|
||||
|
||||
return tcbp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC_REENTRANT
|
||||
/* _dl_error_catch_tsd points to this for the single-threaded case.
|
||||
It's reset by the thread library for multithreaded programs. */
|
||||
@ -702,7 +808,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
hp_timing_t diff;
|
||||
#endif
|
||||
#ifdef USE_TLS
|
||||
void *tcbp;
|
||||
void *tcbp = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC_REENTRANT
|
||||
@ -826,6 +932,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
objects. */
|
||||
_dl_init_paths (library_path);
|
||||
|
||||
|
||||
/* The initialization of _dl_stack_flags done below assumes the
|
||||
executable's PT_GNU_STACK may have been honored by the kernel, and
|
||||
so a PT_GNU_STACK with PF_X set means the stack started out with
|
||||
@ -887,10 +994,10 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
{
|
||||
/* Create a link_map for the executable itself.
|
||||
This will be what dlopen on "" returns. */
|
||||
_dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
|
||||
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
if (main_map == NULL)
|
||||
_dl_fatal_printf ("cannot allocate memory for link map\n");
|
||||
main_map
|
||||
= _dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
|
||||
assert (main_map != NULL);
|
||||
assert (main_map == GL(dl_ns)[LM_ID_BASE]._ns_loaded);
|
||||
main_map->l_phdr = phdr;
|
||||
main_map->l_phnum = phnum;
|
||||
main_map->l_entry = *user_entry;
|
||||
@ -991,8 +1098,9 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
main_map->l_text_end = allocend;
|
||||
}
|
||||
break;
|
||||
#ifdef USE_TLS
|
||||
|
||||
case PT_TLS:
|
||||
#ifdef USE_TLS
|
||||
if (ph->p_memsz > 0)
|
||||
{
|
||||
/* Note that in the case the dynamic linker we duplicate work
|
||||
@ -1012,8 +1120,12 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
/* This image gets the ID one. */
|
||||
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
_dl_fatal_printf ("\
|
||||
ld.so does not support TLS, but program uses it!\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case PT_GNU_STACK:
|
||||
GL(dl_stack_flags) = ph->p_flags;
|
||||
break;
|
||||
@ -1045,6 +1157,26 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
else
|
||||
assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
|
||||
|
||||
/* If the current libname is different from the SONAME, add the
|
||||
latter as well. */
|
||||
if (GL(dl_rtld_map).l_info[DT_SONAME] != NULL
|
||||
&& strcmp (GL(dl_rtld_map).l_libname->name,
|
||||
(const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
|
||||
+ GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val) != 0)
|
||||
{
|
||||
static struct libname_list newname;
|
||||
newname.name = ((char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
|
||||
+ GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_ptr);
|
||||
newname.next = NULL;
|
||||
newname.dont_free = 1;
|
||||
|
||||
assert (GL(dl_rtld_map).l_libname->next == NULL);
|
||||
GL(dl_rtld_map).l_libname->next = &newname;
|
||||
}
|
||||
/* The ld.so must be relocated since otherwise loading audit modules
|
||||
will fail since they reuse the very same ld.so. */
|
||||
assert (GL(dl_rtld_map).l_relocated);
|
||||
|
||||
if (! rtld_is_main)
|
||||
{
|
||||
/* Extract the contents of the dynamic section for easy access. */
|
||||
@ -1074,6 +1206,10 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
objects. */
|
||||
_dl_init_paths (library_path);
|
||||
|
||||
/* Initialize _r_debug. */
|
||||
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
|
||||
/* Put the link_map for ourselves on the chain so it can be found by
|
||||
name. Note that at this point the global chain of link maps contains
|
||||
exactly one element, which is pointed to by dl_loaded. */
|
||||
@ -1101,6 +1237,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
GL(dl_rtld_map).l_phdr = rtld_phdr;
|
||||
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
|
||||
|
||||
|
||||
/* PT_GNU_RELRO is usually the last phdr. */
|
||||
size_t cnt = rtld_ehdr->e_phnum;
|
||||
while (cnt-- > 0)
|
||||
@ -1111,6 +1248,204 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* Add the dynamic linker to the TLS list if it also uses TLS. */
|
||||
if (GL(dl_rtld_map).l_tls_blocksize != 0)
|
||||
/* Assign a module ID. Do this before loading any audit modules. */
|
||||
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
|
||||
#endif
|
||||
|
||||
/* If we have auditing DSOs to load, do it now. */
|
||||
if (__builtin_expect (audit_list != NULL, 0))
|
||||
{
|
||||
/* Iterate over all entries in the list. The order is important. */
|
||||
struct audit_ifaces *last_audit = NULL;
|
||||
struct audit_list *al = audit_list->next;
|
||||
do
|
||||
{
|
||||
#ifdef USE_TLS
|
||||
int tls_idx = GL(dl_tls_max_dtv_idx);
|
||||
|
||||
/* Now it is time to determine the layout of the static TLS
|
||||
block and allocate it for the initial thread. Note that we
|
||||
always allocate the static block, we never defer it even if
|
||||
no DF_STATIC_TLS bit is set. The reason is that we know
|
||||
glibc will use the static model. */
|
||||
# ifndef TLS_INIT_TP_EXPENSIVE
|
||||
# define TLS_INIT_TP_EXPENSIVE 0
|
||||
# endif
|
||||
|
||||
/* Since we start using the auditing DSOs right away we need to
|
||||
initialize the data structures now. */
|
||||
if (!TLS_INIT_TP_EXPENSIVE)
|
||||
tcbp = init_tls ();
|
||||
#endif
|
||||
struct dlmopen_args dlmargs;
|
||||
dlmargs.fname = al->name;
|
||||
dlmargs.map = NULL;
|
||||
|
||||
const char *objname;
|
||||
const char *err_str = NULL;
|
||||
(void) _dl_catch_error (&objname, &err_str, dlmopen_doit, &dlmargs);
|
||||
if (__builtin_expect (err_str != NULL, 0))
|
||||
{
|
||||
not_loaded:
|
||||
_dl_error_printf ("\
|
||||
ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
al->name, err_str);
|
||||
free ((char *) err_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct lookup_args largs;
|
||||
largs.name = "la_version";
|
||||
largs.map = dlmargs.map;
|
||||
|
||||
/* Check whether the interface version matches. */
|
||||
(void) _dl_catch_error (&objname, &err_str, lookup_doit, &largs);
|
||||
|
||||
unsigned int (*laversion) (unsigned int);
|
||||
unsigned int lav;
|
||||
if (err_str == NULL
|
||||
&& (laversion = largs.result) != NULL
|
||||
&& (lav = laversion (LAV_CURRENT)) > 0
|
||||
&& lav <= LAV_CURRENT)
|
||||
{
|
||||
/* Allocate structure for the callback function pointers.
|
||||
This call can never fail. */
|
||||
union
|
||||
{
|
||||
struct audit_ifaces ifaces;
|
||||
#define naudit_ifaces 8
|
||||
void (*fptr[naudit_ifaces]) (void);
|
||||
} *newp = malloc (sizeof (*newp));
|
||||
|
||||
/* Names of the auditing interfaces. All in one
|
||||
long string. */
|
||||
static const char audit_iface_names[] =
|
||||
"la_activity\0"
|
||||
"la_objsearch\0"
|
||||
"la_objopen\0"
|
||||
"la_preinit\0"
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
"la_symbind32\0"
|
||||
#elif __ELF_NATIVE_CLASS == 64
|
||||
"la_symbind64\0"
|
||||
#else
|
||||
# error "__ELF_NATIVE_CLASS must be defined"
|
||||
#endif
|
||||
#define STRING(s) __STRING (s)
|
||||
"la_" STRING (ARCH_LA_PLTENTER) "\0"
|
||||
"la_" STRING (ARCH_LA_PLTEXIT) "\0"
|
||||
"la_objclose\0";
|
||||
unsigned int cnt = 0;
|
||||
const char *cp = audit_iface_names;
|
||||
do
|
||||
{
|
||||
largs.name = cp;
|
||||
(void) _dl_catch_error (&objname, &err_str, lookup_doit,
|
||||
&largs);
|
||||
|
||||
/* Store the pointer. */
|
||||
if (err_str == NULL && largs.result != NULL)
|
||||
{
|
||||
newp->fptr[cnt] = largs.result;
|
||||
|
||||
/* The dynamic linker link map is statically
|
||||
allocated, initialize the data now. */
|
||||
GL(dl_rtld_map).l_audit[cnt].cookie
|
||||
= (intptr_t) &GL(dl_rtld_map);
|
||||
}
|
||||
else
|
||||
newp->fptr[cnt] = NULL;
|
||||
++cnt;
|
||||
|
||||
cp = (char *) rawmemchr (cp, '\0') + 1;
|
||||
}
|
||||
while (*cp != '\0');
|
||||
assert (cnt == naudit_ifaces);
|
||||
|
||||
/* Now append the new auditing interface to the list. */
|
||||
newp->ifaces.next = NULL;
|
||||
if (last_audit == NULL)
|
||||
last_audit = GLRO(dl_audit) = &newp->ifaces;
|
||||
else
|
||||
last_audit = last_audit->next = &newp->ifaces;
|
||||
++GLRO(dl_naudit);
|
||||
|
||||
/* Mark the DSO as being used for auditing. */
|
||||
dlmargs.map->l_auditing = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We cannot use the DSO, it does not have the
|
||||
appropriate interfaces or it expects something
|
||||
more recent. */
|
||||
#ifndef NDEBUG
|
||||
Lmid_t ns = dlmargs.map->l_ns;
|
||||
#endif
|
||||
_dl_close (dlmargs.map);
|
||||
|
||||
/* Make sure the namespace has been cleared entirely. */
|
||||
assert (GL(dl_ns)[ns]._ns_loaded == NULL);
|
||||
assert (GL(dl_ns)[ns]._ns_nloaded == 0);
|
||||
|
||||
#ifdef USE_TLS
|
||||
GL(dl_tls_max_dtv_idx) = tls_idx;
|
||||
#endif
|
||||
goto not_loaded;
|
||||
}
|
||||
}
|
||||
|
||||
al = al->next;
|
||||
}
|
||||
while (al != audit_list->next);
|
||||
|
||||
/* If we have any auditing modules, announce that we already
|
||||
have two objects loaded. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct link_map *ls[2] = { main_map, &GL(dl_rtld_map) };
|
||||
|
||||
for (unsigned int outer = 0; outer < 2; ++outer)
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->objopen != NULL)
|
||||
{
|
||||
ls[outer]->l_audit[cnt].bindflags
|
||||
= afct->objopen (ls[outer], LM_ID_BASE,
|
||||
&ls[outer]->l_audit[cnt].cookie);
|
||||
|
||||
ls[outer]->l_audit_any_plt
|
||||
|= ls[outer]->l_audit[cnt].bindflags != 0;
|
||||
}
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We start adding objects. */
|
||||
r->r_state = RT_ADD;
|
||||
_dl_debug_state ();
|
||||
|
||||
/* Auditing checkpoint: we are ready to signal that the initial map
|
||||
is being constructed. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->activity != NULL)
|
||||
afct->activity (&main_map->l_audit[cnt].cookie, LA_ACT_ADD);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have two ways to specify objects to preload: via environment
|
||||
variable and via the file /etc/ld.so.preload. The latter can also
|
||||
be used when security is enabled. */
|
||||
@ -1310,6 +1645,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
&& ph->p_vaddr + ph->p_memsz >= l->l_text_end)
|
||||
l->l_text_end = ph->p_vaddr + ph->p_memsz;
|
||||
}
|
||||
else
|
||||
/* There must be no TLS segment. */
|
||||
assert (ph->p_type != PT_TLS);
|
||||
}
|
||||
l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
|
||||
l->l_addr = l->l_map_start - l->l_addr;
|
||||
@ -1425,20 +1763,6 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
}
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* Now it is time to determine the layout of the static TLS block
|
||||
and allocate it for the initial thread. Note that we always
|
||||
allocate the static block, we never defer it even if no
|
||||
DF_STATIC_TLS bit is set. The reason is that we know glibc will
|
||||
use the static model. First add the dynamic linker to the list
|
||||
if it also uses TLS. */
|
||||
if (GL(dl_rtld_map).l_tls_blocksize != 0)
|
||||
/* Assign a module ID. */
|
||||
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
|
||||
|
||||
# ifndef TLS_INIT_TP_EXPENSIVE
|
||||
# define TLS_INIT_TP_EXPENSIVE 0
|
||||
# endif
|
||||
|
||||
/* We do not initialize any of the TLS functionality unless any of the
|
||||
initial modules uses TLS. This makes dynamic loading of modules with
|
||||
TLS impossible, but to support it requires either eagerly doing setup
|
||||
@ -1446,57 +1770,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
|
||||
an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
|
||||
used. Trying to do it lazily is too hairy to try when there could be
|
||||
multiple threads (from a non-TLS-using libpthread). */
|
||||
if (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0)
|
||||
{
|
||||
struct link_map *l;
|
||||
size_t nelem;
|
||||
struct dtv_slotinfo *slotinfo;
|
||||
|
||||
/* Number of elements in the static TLS block. */
|
||||
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
|
||||
|
||||
/* Allocate the array which contains the information about the
|
||||
dtv slots. We allocate a few entries more than needed to
|
||||
avoid the need for reallocation. */
|
||||
nelem = GL(dl_tls_max_dtv_idx) + 1 + TLS_SLOTINFO_SURPLUS;
|
||||
|
||||
/* Allocate. */
|
||||
GL(dl_tls_dtv_slotinfo_list) = (struct dtv_slotinfo_list *)
|
||||
malloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ nelem * sizeof (struct dtv_slotinfo));
|
||||
/* No need to check the return value. If memory allocation failed
|
||||
the program would have been terminated. */
|
||||
|
||||
slotinfo = memset (GL(dl_tls_dtv_slotinfo_list)->slotinfo, '\0',
|
||||
nelem * sizeof (struct dtv_slotinfo));
|
||||
GL(dl_tls_dtv_slotinfo_list)->len = nelem;
|
||||
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
|
||||
|
||||
/* Fill in the information from the loaded modules. */
|
||||
for (l = main_map, i = 0; l != NULL; l = l->l_next)
|
||||
if (l->l_tls_blocksize != 0)
|
||||
/* This is a module with TLS data. Store the map reference.
|
||||
The generation counter is zero. */
|
||||
slotinfo[++i].map = l;
|
||||
assert (i == GL(dl_tls_max_dtv_idx));
|
||||
|
||||
/* Compute the TLS offsets for the various blocks. */
|
||||
_dl_determine_tlsoffset ();
|
||||
|
||||
/* Construct the static TLS block and the dtv for the initial
|
||||
thread. For some platforms this will include allocating memory
|
||||
for the thread descriptor. The memory for the TLS block will
|
||||
never be freed. It should be allocated accordingly. The dtv
|
||||
array can be changed if dynamic loading requires it. */
|
||||
tcbp = _dl_allocate_tls_storage ();
|
||||
if (tcbp == NULL)
|
||||
_dl_fatal_printf ("\
|
||||
cannot allocate TLS data structures for initial thread");
|
||||
|
||||
/* Store for detection of the special case by __tls_get_addr
|
||||
so it knows not to pass this dtv to the normal realloc. */
|
||||
GL(dl_initial_dtv) = GET_DTV (tcbp);
|
||||
}
|
||||
bool was_tls_init_tp_called = tls_init_tp_called;
|
||||
if (tcbp == NULL && (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0))
|
||||
tcbp = init_tls ();
|
||||
#endif
|
||||
|
||||
if (__builtin_expect (mode, normal) != normal)
|
||||
@ -1777,8 +2053,6 @@ cannot allocate TLS data structures for initial thread");
|
||||
}
|
||||
|
||||
|
||||
/* Initialize _r_debug. */
|
||||
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);
|
||||
{
|
||||
struct link_map *l = main_map;
|
||||
|
||||
@ -1813,8 +2087,6 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
if (prelinked)
|
||||
{
|
||||
struct link_map *l;
|
||||
|
||||
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
|
||||
{
|
||||
ElfW(Rela) *conflict, *conflictend;
|
||||
@ -1837,11 +2109,15 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
|
||||
/* Mark all the objects so we know they have been already relocated. */
|
||||
for (l = main_map; l != NULL; l = l->l_next)
|
||||
for (struct link_map *l = main_map; l != NULL; l = l->l_next)
|
||||
{
|
||||
l->l_relocated = 1;
|
||||
if (l->l_relro_size)
|
||||
_dl_protect_relro (l);
|
||||
|
||||
/* Add object to slot information data if necessasy. */
|
||||
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
|
||||
_dl_add_to_slotinfo (l);
|
||||
}
|
||||
|
||||
_dl_sysdep_start_cleanup ();
|
||||
@ -1857,7 +2133,6 @@ cannot allocate TLS data structures for initial thread");
|
||||
the dynamic linker out of order because it has no copy relocs (we
|
||||
know that because it is self-contained). */
|
||||
|
||||
struct link_map *l;
|
||||
int consider_profiling = GLRO(dl_profile) != NULL;
|
||||
#ifndef HP_TIMING_NONAVAIL
|
||||
hp_timing_t start;
|
||||
@ -1868,7 +2143,7 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* If we are profiling we also must do lazy reloaction. */
|
||||
GLRO(dl_lazy) |= consider_profiling;
|
||||
|
||||
l = main_map;
|
||||
struct link_map *l = main_map;
|
||||
while (l->l_next)
|
||||
l = l->l_next;
|
||||
|
||||
@ -1890,6 +2165,10 @@ cannot allocate TLS data structures for initial thread");
|
||||
_dl_relocate_object (l, l->l_scope, GLRO(dl_lazy),
|
||||
consider_profiling);
|
||||
|
||||
/* Add object to slot information data if necessasy. */
|
||||
if (l->l_tls_blocksize != 0 && tls_init_tp_called)
|
||||
_dl_add_to_slotinfo (l);
|
||||
|
||||
l = l->l_prev;
|
||||
}
|
||||
while (l);
|
||||
@ -1917,6 +2196,8 @@ cannot allocate TLS data structures for initial thread");
|
||||
/* There was an explicit ref to the dynamic linker as a shared lib.
|
||||
Re-relocate ourselves with user-controlled symbol definitions. */
|
||||
HP_TIMING_NOW (start);
|
||||
/* Mark the link map as not yet relocated again. */
|
||||
GL(dl_rtld_map).l_relocated = 0;
|
||||
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (add, start, stop);
|
||||
@ -1931,6 +2212,9 @@ cannot allocate TLS data structures for initial thread");
|
||||
#ifdef USE_TLS
|
||||
if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD || !TLS_INIT_TP_EXPENSIVE)
|
||||
{
|
||||
if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
|
||||
++GL(dl_tls_generation);
|
||||
|
||||
/* Now that we have completed relocation, the initializer data
|
||||
for the TLS blocks has its final values and we can copy them
|
||||
into the main thread's TLS area, which we allocated above. */
|
||||
@ -1938,16 +2222,42 @@ cannot allocate TLS data structures for initial thread");
|
||||
|
||||
/* And finally install it for the main thread. If ld.so itself uses
|
||||
TLS we know the thread pointer was initialized earlier. */
|
||||
const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
|
||||
if (__builtin_expect (lossage != NULL, 0))
|
||||
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
|
||||
if (! tls_init_tp_called)
|
||||
{
|
||||
const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
|
||||
if (__builtin_expect (lossage != NULL, 0))
|
||||
_dl_fatal_printf ("cannot set up thread-local storage: %s\n",
|
||||
lossage);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
NONTLS_INIT_TP;
|
||||
|
||||
/* Notify the debugger that all objects are now mapped in. */
|
||||
r->r_state = RT_ADD;
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have added all objects. */
|
||||
if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
|
||||
{
|
||||
struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
/* Do not call the functions for any auditing object. */
|
||||
if (head->l_auditing == 0)
|
||||
{
|
||||
struct audit_ifaces *afct = GLRO(dl_audit);
|
||||
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
|
||||
{
|
||||
if (afct->activity != NULL)
|
||||
afct->activity (&head->l_audit[cnt].cookie, LA_ACT_CONSISTENT);
|
||||
|
||||
afct = afct->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Notify the debugger all new objects are now ready to go. We must re-get
|
||||
the address since by now the variable might be in another object. */
|
||||
r = _dl_debug_initialize (0);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
|
||||
#ifndef MAP_COPY
|
||||
@ -2079,6 +2389,32 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_dl_audit (char *str)
|
||||
{
|
||||
/* The parameter is a colon separated list of DSO names. */
|
||||
char *p;
|
||||
|
||||
while ((p = (strsep) (&str, ":")) != NULL)
|
||||
if (p[0] != '\0'
|
||||
&& (__builtin_expect (! INTUSE(__libc_enable_secure), 1)
|
||||
|| strchr (p, '/') == NULL))
|
||||
{
|
||||
/* This is using the local malloc, not the system malloc. The
|
||||
memory can never be freed. */
|
||||
struct audit_list *newp = malloc (sizeof (*newp));
|
||||
newp->name = p;
|
||||
|
||||
if (audit_list == NULL)
|
||||
audit_list = newp->next = newp;
|
||||
else
|
||||
{
|
||||
newp->next = audit_list->next;
|
||||
audit_list = audit_list->next = newp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@ -2121,7 +2457,12 @@ process_envvars (enum mode *modep)
|
||||
case 5:
|
||||
/* Debugging of the dynamic linker? */
|
||||
if (memcmp (envline, "DEBUG", 5) == 0)
|
||||
process_dl_debug (&envline[6]);
|
||||
{
|
||||
process_dl_debug (&envline[6]);
|
||||
break;
|
||||
}
|
||||
if (memcmp (envline, "AUDIT", 5) == 0)
|
||||
process_dl_audit (&envline[6]);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
|
1
elf/tst-audit1.c
Normal file
1
elf/tst-audit1.c
Normal file
@ -0,0 +1 @@
|
||||
#include "../io/pwd.c"
|
153
elf/tst-auditmod1.c
Normal file
153
elf/tst-auditmod1.c
Normal file
@ -0,0 +1,153 @@
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
|
||||
unsigned int
|
||||
la_version (unsigned int v)
|
||||
{
|
||||
setlinebuf (stdout);
|
||||
|
||||
printf ("version: %u\n", v);
|
||||
|
||||
char buf[20];
|
||||
sprintf (buf, "%u", v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
la_activity (uintptr_t *cookie, unsigned int flag)
|
||||
{
|
||||
if (flag == LA_ACT_CONSISTENT)
|
||||
printf ("activity: consistent\n");
|
||||
else if (flag == LA_ACT_ADD)
|
||||
printf ("activity: add\n");
|
||||
else if (flag == LA_ACT_DELETE)
|
||||
printf ("activity: delete\n");
|
||||
else
|
||||
printf ("activity: unknown activity %u\n", flag);
|
||||
}
|
||||
|
||||
char *
|
||||
la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag)
|
||||
{
|
||||
char buf[100];
|
||||
const char *flagstr;
|
||||
if (flag == LA_SER_ORIG)
|
||||
flagstr = "LA_SET_ORIG";
|
||||
else if (flag == LA_SER_LIBPATH)
|
||||
flagstr = "LA_SER_LIBPATH";
|
||||
else if (flag == LA_SER_RUNPATH)
|
||||
flagstr = "LA_SER_RUNPATH";
|
||||
else if (flag == LA_SER_CONFIG)
|
||||
flagstr = "LA_SER_CONFIG";
|
||||
else if (flag == LA_SER_DEFAULT)
|
||||
flagstr = "LA_SER_DEFAULT";
|
||||
else if (flag == LA_SER_SECURE)
|
||||
flagstr = "LA_SER_SECURE";
|
||||
else
|
||||
{
|
||||
sprintf (buf, "unknown flag %d", flag);
|
||||
flagstr = buf;
|
||||
}
|
||||
printf ("objsearch: %s, %s\n", name, flagstr);
|
||||
|
||||
return (char *) name;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
la_objopen (struct link_map *l, Lmid_t lmid, uintptr_t *cookie)
|
||||
{
|
||||
printf ("objopen: %ld, %s\n", lmid, l->l_name);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
void
|
||||
la_preinit (uintptr_t *cookie)
|
||||
{
|
||||
printf ("preinit\n");
|
||||
}
|
||||
|
||||
unsigned int
|
||||
la_objclose (uintptr_t *cookie)
|
||||
{
|
||||
printf ("objclose\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||
uintptr_t *defcook, unsigned int *flags, const char *symname)
|
||||
{
|
||||
printf ("symbind32: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
|
||||
symname, (long int) sym->st_value, ndx, *flags);
|
||||
|
||||
return sym->st_value;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||
uintptr_t *defcook, unsigned int *flags, const char *symname)
|
||||
{
|
||||
printf ("symbind64: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
|
||||
symname, (long int) sym->st_value, ndx, *flags);
|
||||
|
||||
return sym->st_value;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
Elf32_Addr
|
||||
la_i86_gnu_pltenter (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||
uintptr_t *defcook, La_i86_regs *regs,
|
||||
unsigned int *flags, const char *symname,
|
||||
long int *framesizep)
|
||||
{
|
||||
printf ("i86_pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
|
||||
symname, (long int) sym->st_value, ndx, *flags);
|
||||
|
||||
return sym->st_value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
la_i86_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||
uintptr_t *defcook, const La_i86_regs *inregs,
|
||||
La_i86_retval *outregs, const char *symname)
|
||||
{
|
||||
printf ("i86_pltexit: symname=%s, st_value=%#lx, ndx=%u, retval=%tu\n",
|
||||
symname, (long int) sym->st_value, ndx, outregs->lrv_eax);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
uintptr_t
|
||||
la_x86_64_gnu_pltenter (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||
uintptr_t *defcook, La_x86_64_regs *regs,
|
||||
unsigned int *flags, const char *symname,
|
||||
long int *framesizep)
|
||||
{
|
||||
printf ("x86_64_pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n",
|
||||
symname, (long int) sym->st_value, ndx, *flags);
|
||||
|
||||
return sym->st_value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
la_x86_64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
|
||||
uintptr_t *defcook, const La_x86_64_regs *inregs,
|
||||
La_x86_64_retval *outregs, const char *symname)
|
||||
{
|
||||
printf ("x86_64_pltexit: symname=%s, st_value=%#lx, ndx=%u, retval=%tu\n",
|
||||
symname, (long int) sym->st_value, ndx, outregs->lrv_rax);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -7,9 +7,24 @@
|
||||
#define __RTLD_SPROF 0x40000000
|
||||
#define __RTLD_OPENEXEC 0x20000000
|
||||
#define __RTLD_CALLMAP 0x10000000
|
||||
#define __RTLD_AUDIT 0x08000000
|
||||
|
||||
#define __LM_ID_CALLER -2
|
||||
|
||||
#ifdef SHARED
|
||||
/* Locally stored program arguments. */
|
||||
extern int __dlfcn_argc attribute_hidden;
|
||||
extern char **__dlfcn_argv attribute_hidden;
|
||||
#else
|
||||
/* These variables are defined and initialized in the startup code. */
|
||||
extern int __libc_argc attribute_hidden;
|
||||
extern char **__libc_argv attribute_hidden;
|
||||
|
||||
# define __dlfcn_argc __libc_argc
|
||||
# define __dlfcn_argv __libc_argv
|
||||
#endif
|
||||
|
||||
|
||||
/* Now define the internal interfaces. */
|
||||
|
||||
#define __libc_dlopen(name) \
|
||||
@ -29,18 +44,8 @@ extern int _dl_addr (const void *address, Dl_info *info,
|
||||
libc_hidden_proto (_dl_addr)
|
||||
#endif
|
||||
|
||||
/* Open the shared object NAME, relocate it, and run its initializer if it
|
||||
hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If
|
||||
the object is already opened, returns its existing map. */
|
||||
extern void *_dl_open (const char *name, int mode, const void *caller,
|
||||
Lmid_t nsid)
|
||||
internal_function;
|
||||
libc_hidden_proto (_dl_open)
|
||||
|
||||
/* Close an object previously opened by _dl_open. */
|
||||
extern void _dl_close (void *map)
|
||||
internal_function;
|
||||
libc_hidden_proto (_dl_close)
|
||||
extern void _dl_close (void *map) attribute_hidden;
|
||||
|
||||
/* Look up NAME in shared object HANDLE (which may be RTLD_DEFAULT or
|
||||
RTLD_NEXT). WHO is the calling function, for RTLD_NEXT. Returns
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
#include <bits/linkmap.h>
|
||||
#include <dl-lookupcfg.h>
|
||||
#include <tls.h> /* Defines USE_TLS. */
|
||||
|
||||
@ -199,6 +200,10 @@ struct link_map
|
||||
should be called on this link map
|
||||
when relocation finishes. */
|
||||
unsigned int l_used:1; /* Nonzero if the DSO is used. */
|
||||
unsigned int l_auditing:1; /* Nonzero if the DSO is used in auditing. */
|
||||
unsigned int l_audit_any_plt:1; /* Nonzero if at least one audit module
|
||||
is interested in the PLT interception.*/
|
||||
|
||||
/* Array with version names. */
|
||||
unsigned int l_nversions;
|
||||
struct r_found_version *l_versions;
|
||||
@ -207,7 +212,14 @@ struct link_map
|
||||
struct r_search_path_struct l_rpath_dirs;
|
||||
|
||||
/* Collected results of relocation while profiling. */
|
||||
ElfW(Addr) *l_reloc_result;
|
||||
struct reloc_result
|
||||
{
|
||||
ElfW(Addr) addr;
|
||||
struct link_map *bound;
|
||||
unsigned int boundndx;
|
||||
uint32_t enterexit;
|
||||
unsigned int flags;
|
||||
} *l_reloc_result;
|
||||
|
||||
/* Pointer to the version information if available. */
|
||||
ElfW(Versym) *l_versyms;
|
||||
@ -263,11 +275,7 @@ struct link_map
|
||||
{
|
||||
const ElfW(Sym) *sym;
|
||||
int type_class;
|
||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
||||
struct link_map *value;
|
||||
#else
|
||||
ElfW(Addr) value;
|
||||
#endif
|
||||
const ElfW(Sym) *ret;
|
||||
} l_lookup_cache;
|
||||
|
||||
@ -297,8 +305,65 @@ struct link_map
|
||||
done. */
|
||||
ElfW(Addr) l_relro_addr;
|
||||
size_t l_relro_size;
|
||||
|
||||
/* Audit information. This array apparent must be the last in the
|
||||
structure. Never add something after it. */
|
||||
struct auditstate
|
||||
{
|
||||
uintptr_t cookie;
|
||||
unsigned int bindflags;
|
||||
} l_audit[0];
|
||||
};
|
||||
|
||||
/* Version numbers for la_version handshake interface. */
|
||||
#define LAV_CURRENT 1
|
||||
|
||||
/* Activity types signaled through la_activity. */
|
||||
enum
|
||||
{
|
||||
LA_ACT_CONSISTENT,
|
||||
LA_ACT_ADD,
|
||||
LA_ACT_DELETE
|
||||
};
|
||||
|
||||
/* Values representing origin of name for dynamic loading. */
|
||||
enum
|
||||
{
|
||||
LA_SER_ORIG = 0x01, /* Original name. */
|
||||
LA_SER_LIBPATH = 0x02, /* Directory from LD_LIBRARY_PATH. */
|
||||
LA_SER_RUNPATH = 0x04, /* Directory from RPATH/RUNPATH. */
|
||||
LA_SER_CONFIG = 0x08, /* Found through ldconfig. */
|
||||
LA_SER_DEFAULT = 0x40, /* Default directory. */
|
||||
LA_SER_SECURE = 0x80 /* Unused. */
|
||||
};
|
||||
|
||||
/* Values for la_objopen return value. */
|
||||
enum
|
||||
{
|
||||
LA_FLG_BINDTO = 0x01, /* Audit symbols bound to this object. */
|
||||
LA_FLG_BINDFROM = 0x02 /* Audit symbols bound from this object. */
|
||||
};
|
||||
|
||||
/* Values for la_symbind flags parameter. */
|
||||
enum
|
||||
{
|
||||
LA_SYMB_NOPLTENTER = 0x01, /* la_pltenter will not be called. */
|
||||
LA_SYMB_NOPLTEXIT = 0x02, /* la_pltexit will not be called. */
|
||||
LA_SYMB_STRUCTCALL = 0x04, /* Return value is a structure. */
|
||||
LA_SYMB_DLSYM = 0x08, /* Binding due to dlsym call. */
|
||||
LA_SYMB_ALTVALUE = 0x10 /* Value has been changed by a previous
|
||||
la_symbind call. */
|
||||
};
|
||||
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
# define symbind symbind32
|
||||
# define pltenter plt
|
||||
#elif __ELF_NATIVE_CLASS == 64
|
||||
# define symbind symbind64
|
||||
#else
|
||||
# error "__ELF_NATIVE_CLASS must be defined"
|
||||
#endif
|
||||
|
||||
struct dl_phdr_info
|
||||
{
|
||||
ElfW(Addr) dlpi_addr;
|
||||
|
@ -1,3 +1,18 @@
|
||||
2005-01-06 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* allocatestack.c (init_one_static_tls): Adjust initialization of DTV
|
||||
entry for static tls deallocation fix.
|
||||
* sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which
|
||||
also contains information whether the memory pointed to is static
|
||||
TLS or not.
|
||||
* sysdeps/i386/tls.h: Likewise.
|
||||
* sysdeps/ia64/tls.h: Likewise.
|
||||
* sysdeps/powerpc/tls.h: Likewise.
|
||||
* sysdeps/s390/tls.h: Likewise.
|
||||
* sysdeps/sh/tls.h: Likewise.
|
||||
* sysdeps/sparc/tls.h: Likewise.
|
||||
* sysdeps/x86_64/tls.h: Likewise.
|
||||
|
||||
2004-12-27 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* init.c (__pthread_initialize_minimal_internal): Use __sigemptyset.
|
||||
|
@ -920,7 +920,8 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
|
||||
# endif
|
||||
|
||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
||||
dtv[map->l_tls_modid].pointer = dest;
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
|
||||
/* Initialize the memory. */
|
||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definition for thread-local data handling. NPTL/Alpha version.
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -23,6 +23,7 @@
|
||||
# include <dl-sysdep.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
@ -30,7 +31,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <dl-sysdep.h>
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
# include <stdlib.h>
|
||||
@ -32,7 +33,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definition for thread-local data handling. nptl/IA-64 version.
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <dl-sysdep.h>
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
# include <stdlib.h>
|
||||
@ -32,7 +33,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definition for thread-local data handling. NPTL/PowerPC version.
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -23,6 +23,7 @@
|
||||
# include <dl-sysdep.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
@ -30,7 +31,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definition for thread-local data handling. NPTL/s390 version.
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <dl-sysdep.h>
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
# include <stdlib.h>
|
||||
@ -32,7 +33,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definition for thread-local data handling. NPTL/SH version.
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -23,6 +23,7 @@
|
||||
# include <dl-sysdep.h>
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
@ -30,7 +31,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definitions for thread-local data handling. NPTL/sparc version.
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <dl-sysdep.h>
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
# include <stdlib.h>
|
||||
@ -31,7 +32,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Definition for thread-local data handling. nptl/x86_64 version.
|
||||
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <asm/prctl.h> /* For ARCH_SET_FS. */
|
||||
#ifndef __ASSEMBLER__
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
# include <stdlib.h>
|
||||
@ -31,7 +32,11 @@
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt */
|
||||
};
|
4
sysdeps/arm/bits/linkmap.h
Normal file
4
sysdeps/arm/bits/linkmap.h
Normal file
@ -0,0 +1,4 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt */
|
||||
};
|
@ -1,4 +1 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
/* empty by default */
|
||||
};
|
||||
#error "Architecture-specific definition needed."
|
||||
|
4
sysdeps/generic/bits/linkmap.h
Normal file
4
sysdeps/generic/bits/linkmap.h
Normal file
@ -0,0 +1,4 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
/* empty by default */
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/* Configuration of lookup functions.
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
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
|
||||
@ -17,16 +17,4 @@
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
/* Some platforms need more information from the symbol lookup function
|
||||
than just the address. But this is not generally the case.
|
||||
|
||||
However, because of how _dl_sym and _dl_tls_symaddr are written, every
|
||||
platform needs it when we support TLS. */
|
||||
|
||||
#include <tls.h> /* Defines USE_TLS (or doesn't). */
|
||||
|
||||
#ifdef USE_TLS
|
||||
# define DL_LOOKUP_RETURNS_MAP
|
||||
#else
|
||||
# undef DL_LOOKUP_RETURNS_MAP
|
||||
#endif
|
||||
/* Nothing special. */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
|
||||
Copyright (C) 2002, 2003, 2004 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
|
||||
@ -18,6 +18,8 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@ -116,10 +118,9 @@ void
|
||||
internal_function
|
||||
_dl_determine_tlsoffset (void)
|
||||
{
|
||||
struct dtv_slotinfo *slotinfo;
|
||||
size_t max_align = TLS_TCB_ALIGN;
|
||||
size_t offset, freetop = 0, freebottom = 0;
|
||||
size_t cnt;
|
||||
size_t freetop = 0;
|
||||
size_t freebottom = 0;
|
||||
|
||||
/* The first element of the dtv slot info list is allocated. */
|
||||
assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
|
||||
@ -127,7 +128,7 @@ _dl_determine_tlsoffset (void)
|
||||
dl_tls_dtv_slotinfo_list list. */
|
||||
assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
|
||||
|
||||
slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
|
||||
struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
|
||||
|
||||
/* Determining the offset of the various parts of the static TLS
|
||||
block has several dependencies. In addition we have to work
|
||||
@ -159,9 +160,9 @@ _dl_determine_tlsoffset (void)
|
||||
|
||||
# if TLS_TCB_AT_TP
|
||||
/* We simply start with zero. */
|
||||
offset = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
|
||||
for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
|
||||
{
|
||||
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
|
||||
|
||||
@ -206,9 +207,9 @@ _dl_determine_tlsoffset (void)
|
||||
+ TLS_TCB_SIZE);
|
||||
# elif TLS_DTV_AT_TP
|
||||
/* The TLS blocks start right after the TCB. */
|
||||
offset = TLS_TCB_SIZE;
|
||||
size_t offset = TLS_TCB_SIZE;
|
||||
|
||||
for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
|
||||
for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
|
||||
{
|
||||
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
|
||||
|
||||
@ -225,8 +226,8 @@ _dl_determine_tlsoffset (void)
|
||||
if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
|
||||
{
|
||||
slotinfo[cnt].map->l_tls_offset = off - firstbyte;
|
||||
freebottom = off + slotinfo[cnt].map->l_tls_blocksize
|
||||
- firstbyte;
|
||||
freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
|
||||
- firstbyte);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -357,14 +358,14 @@ _dl_allocate_tls_storage (void)
|
||||
|
||||
/* Clear the TCB data structure. We can't ask the caller (i.e.
|
||||
libpthread) to do it, because we will initialize the DTV et al. */
|
||||
memset (result, 0, TLS_TCB_SIZE);
|
||||
memset (result, '\0', TLS_TCB_SIZE);
|
||||
# elif TLS_DTV_AT_TP
|
||||
result = (char *) result + size - GL(dl_tls_static_size);
|
||||
|
||||
/* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
|
||||
We can't ask the caller (i.e. libpthread) to do it, because we will
|
||||
initialize the DTV et al. */
|
||||
memset ((char *) result - TLS_PRE_TCB_SIZE, 0,
|
||||
memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
|
||||
TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
|
||||
# endif
|
||||
|
||||
@ -388,10 +389,11 @@ _dl_allocate_tls_init (void *result)
|
||||
dtv_t *dtv = GET_DTV (result);
|
||||
struct dtv_slotinfo_list *listp;
|
||||
size_t total = 0;
|
||||
size_t maxgen = 0;
|
||||
|
||||
/* We have to look prepare the dtv for all currently loaded
|
||||
modules using TLS. For those which are dynamically loaded we
|
||||
add the values indicating deferred allocation. */
|
||||
/* We have to prepare the dtv for all currently loaded modules using
|
||||
TLS. For those which are dynamically loaded we add the values
|
||||
indicating deferred allocation. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
while (1)
|
||||
{
|
||||
@ -411,11 +413,16 @@ _dl_allocate_tls_init (void *result)
|
||||
/* Unused entry. */
|
||||
continue;
|
||||
|
||||
/* Keep track of the maximum generation number. This might
|
||||
not be the generation counter. */
|
||||
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
||||
|
||||
if (map->l_tls_offset == NO_TLS_OFFSET)
|
||||
{
|
||||
/* For dynamically loaded modules we simply store
|
||||
the value indicating deferred allocation. */
|
||||
dtv[map->l_tls_modid].pointer = TLS_DTV_UNALLOCATED;
|
||||
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[map->l_tls_modid].pointer.is_static = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -431,7 +438,8 @@ _dl_allocate_tls_init (void *result)
|
||||
# endif
|
||||
|
||||
/* Copy the initialization image and clear the BSS part. */
|
||||
dtv[map->l_tls_modid].pointer = dest;
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size), '\0',
|
||||
map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
@ -445,6 +453,9 @@ _dl_allocate_tls_init (void *result)
|
||||
assert (listp != NULL);
|
||||
}
|
||||
|
||||
/* The DTV version is up-to-date now. */
|
||||
dtv[0].counter = maxgen;
|
||||
|
||||
return result;
|
||||
}
|
||||
rtld_hidden_def (_dl_allocate_tls_init)
|
||||
@ -466,6 +477,12 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
|
||||
{
|
||||
dtv_t *dtv = GET_DTV (tcb);
|
||||
|
||||
/* We need to free the memory allocated for non-static TLS. */
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
if (! dtv[1 + cnt].pointer.is_static
|
||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
free (dtv[1 + cnt].pointer.val);
|
||||
|
||||
/* The array starts with dtv[-1]. */
|
||||
#ifdef SHARED
|
||||
if (dtv != GL(dl_initial_dtv))
|
||||
@ -524,6 +541,159 @@ allocate_and_init (struct link_map *map)
|
||||
}
|
||||
|
||||
|
||||
struct link_map *
|
||||
_dl_update_slotinfo (unsigned long int req_modid)
|
||||
{
|
||||
struct link_map *the_map = NULL;
|
||||
dtv_t *dtv = THREAD_DTV ();
|
||||
|
||||
/* The global dl_tls_dtv_slotinfo array contains for each module
|
||||
index the generation counter current when the entry was created.
|
||||
This array never shrinks so that all module indices which were
|
||||
valid at some time can be used to access it. Before the first
|
||||
use of a new module index in this function the array was extended
|
||||
appropriately. Access also does not have to be guarded against
|
||||
modifications of the array. It is assumed that pointer-size
|
||||
values can be read atomically even in SMP environments. It is
|
||||
possible that other threads at the same time dynamically load
|
||||
code and therefore add to the slotinfo list. This is a problem
|
||||
since we must not pick up any information about incomplete work.
|
||||
The solution to this is to ignore all dtv slots which were
|
||||
created after the one we are currently interested. We know that
|
||||
dynamic loading for this module is completed and this is the last
|
||||
load operation we know finished. */
|
||||
unsigned long int idx = req_modid;
|
||||
struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
|
||||
while (idx >= listp->len)
|
||||
{
|
||||
idx -= listp->len;
|
||||
listp = listp->next;
|
||||
}
|
||||
|
||||
if (dtv[0].counter < listp->slotinfo[idx].gen)
|
||||
{
|
||||
/* The generation counter for the slot is higher than what the
|
||||
current dtv implements. We have to update the whole dtv but
|
||||
only those entries with a generation counter <= the one for
|
||||
the entry we need. */
|
||||
size_t new_gen = listp->slotinfo[idx].gen;
|
||||
size_t total = 0;
|
||||
|
||||
/* We have to look through the entire dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
do
|
||||
{
|
||||
for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
|
||||
{
|
||||
size_t gen = listp->slotinfo[cnt].gen;
|
||||
|
||||
if (gen > new_gen)
|
||||
/* This is a slot for a generation younger than the
|
||||
one we are handling now. It might be incompletely
|
||||
set up so ignore it. */
|
||||
continue;
|
||||
|
||||
/* If the entry is older than the current dtv layout we
|
||||
know we don't have to handle it. */
|
||||
if (gen <= dtv[0].counter)
|
||||
continue;
|
||||
|
||||
/* If there is no map this means the entry is empty. */
|
||||
struct link_map *map = listp->slotinfo[cnt].map;
|
||||
if (map == NULL)
|
||||
{
|
||||
/* If this modid was used at some point the memory
|
||||
might still be allocated. */
|
||||
if (! dtv[total + cnt].pointer.is_static
|
||||
&& dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
free (dtv[total + cnt].pointer.val);
|
||||
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check whether the current dtv array is large enough. */
|
||||
size_t modid = map->l_tls_modid;
|
||||
assert (total + cnt == modid);
|
||||
if (dtv[-1].counter < modid)
|
||||
{
|
||||
/* Reallocate the dtv. */
|
||||
dtv_t *newp;
|
||||
size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
|
||||
size_t oldsize = dtv[-1].counter;
|
||||
|
||||
assert (map->l_tls_modid <= newsize);
|
||||
|
||||
if (dtv == GL(dl_initial_dtv))
|
||||
{
|
||||
/* This is the initial dtv that was allocated
|
||||
during rtld startup using the dl-minimal.c
|
||||
malloc instead of the real malloc. We can't
|
||||
free it, we have to abandon the old storage. */
|
||||
|
||||
newp = malloc ((2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
newp = realloc (&dtv[-1],
|
||||
(2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
}
|
||||
|
||||
newp[0].counter = newsize;
|
||||
|
||||
/* Clear the newly allocated part. */
|
||||
memset (newp + 2 + oldsize, '\0',
|
||||
(newsize - oldsize) * sizeof (dtv_t));
|
||||
|
||||
/* Point dtv to the generation counter. */
|
||||
dtv = &newp[1];
|
||||
|
||||
/* Install this new dtv in the thread data
|
||||
structures. */
|
||||
INSTALL_NEW_DTV (dtv);
|
||||
}
|
||||
|
||||
/* If there is currently memory allocate for this
|
||||
dtv entry free it. */
|
||||
/* XXX Ideally we will at some point create a memory
|
||||
pool. */
|
||||
if (! dtv[modid].pointer.is_static
|
||||
&& dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
/* Note that free is called for NULL is well. We
|
||||
deallocate even if it is this dtv entry we are
|
||||
supposed to load. The reason is that we call
|
||||
memalign and not malloc. */
|
||||
free (dtv[modid].pointer.val);
|
||||
|
||||
/* This module is loaded dynamically- We defer memory
|
||||
allocation. */
|
||||
dtv[modid].pointer.is_static = false;
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
|
||||
if (modid == req_modid)
|
||||
the_map = map;
|
||||
}
|
||||
|
||||
total += listp->len;
|
||||
}
|
||||
while ((listp = listp->next) != NULL);
|
||||
|
||||
/* This will be the new maximum generation counter. */
|
||||
dtv[0].counter = new_gen;
|
||||
}
|
||||
|
||||
return the_map;
|
||||
}
|
||||
|
||||
|
||||
/* The generic dynamic and local dynamic model cannot be used in
|
||||
statically linked applications. */
|
||||
void *
|
||||
@ -534,156 +704,9 @@ __tls_get_addr (GET_ADDR_ARGS)
|
||||
void *p;
|
||||
|
||||
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
|
||||
{
|
||||
struct dtv_slotinfo_list *listp;
|
||||
size_t idx;
|
||||
the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
|
||||
|
||||
/* The global dl_tls_dtv_slotinfo array contains for each module
|
||||
index the generation counter current when the entry was
|
||||
created. This array never shrinks so that all module indices
|
||||
which were valid at some time can be used to access it.
|
||||
Before the first use of a new module index in this function
|
||||
the array was extended appropriately. Access also does not
|
||||
have to be guarded against modifications of the array. It is
|
||||
assumed that pointer-size values can be read atomically even
|
||||
in SMP environments. It is possible that other threads at
|
||||
the same time dynamically load code and therefore add to the
|
||||
slotinfo list. This is a problem since we must not pick up
|
||||
any information about incomplete work. The solution to this
|
||||
is to ignore all dtv slots which were created after the one
|
||||
we are currently interested. We know that dynamic loading
|
||||
for this module is completed and this is the last load
|
||||
operation we know finished. */
|
||||
idx = GET_ADDR_MODULE;
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
while (idx >= listp->len)
|
||||
{
|
||||
idx -= listp->len;
|
||||
listp = listp->next;
|
||||
}
|
||||
|
||||
if (dtv[0].counter < listp->slotinfo[idx].gen)
|
||||
{
|
||||
/* The generation counter for the slot is higher than what
|
||||
the current dtv implements. We have to update the whole
|
||||
dtv but only those entries with a generation counter <=
|
||||
the one for the entry we need. */
|
||||
size_t new_gen = listp->slotinfo[idx].gen;
|
||||
size_t total = 0;
|
||||
|
||||
/* We have to look through the entire dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
do
|
||||
{
|
||||
size_t cnt;
|
||||
|
||||
for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
|
||||
{
|
||||
size_t gen = listp->slotinfo[cnt].gen;
|
||||
struct link_map *map;
|
||||
size_t modid;
|
||||
|
||||
if (gen > new_gen)
|
||||
/* This is a slot for a generation younger than
|
||||
the one we are handling now. It might be
|
||||
incompletely set up so ignore it. */
|
||||
continue;
|
||||
|
||||
/* If the entry is older than the current dtv layout
|
||||
we know we don't have to handle it. */
|
||||
if (gen <= dtv[0].counter)
|
||||
continue;
|
||||
|
||||
/* If there is no map this means the entry is empty. */
|
||||
map = listp->slotinfo[cnt].map;
|
||||
if (map == NULL)
|
||||
{
|
||||
/* If this modid was used at some point the memory
|
||||
might still be allocated. */
|
||||
if (dtv[total + cnt].pointer != TLS_DTV_UNALLOCATED)
|
||||
{
|
||||
free (dtv[total + cnt].pointer);
|
||||
dtv[total + cnt].pointer = TLS_DTV_UNALLOCATED;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check whether the current dtv array is large enough. */
|
||||
modid = map->l_tls_modid;
|
||||
assert (total + cnt == modid);
|
||||
if (dtv[-1].counter < modid)
|
||||
{
|
||||
/* Reallocate the dtv. */
|
||||
dtv_t *newp;
|
||||
size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
|
||||
size_t oldsize = dtv[-1].counter;
|
||||
|
||||
assert (map->l_tls_modid <= newsize);
|
||||
|
||||
if (dtv == GL(dl_initial_dtv))
|
||||
{
|
||||
/* This is the initial dtv that was allocated
|
||||
during rtld startup using the dl-minimal.c
|
||||
malloc instead of the real malloc. We can't
|
||||
free it, we have to abandon the old storage. */
|
||||
|
||||
newp = malloc ((2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
newp = realloc (&dtv[-1],
|
||||
(2 + newsize) * sizeof (dtv_t));
|
||||
if (newp == NULL)
|
||||
oom ();
|
||||
}
|
||||
|
||||
newp[0].counter = newsize;
|
||||
|
||||
/* Clear the newly allocated part. */
|
||||
memset (newp + 2 + oldsize, '\0',
|
||||
(newsize - oldsize) * sizeof (dtv_t));
|
||||
|
||||
/* Point dtv to the generation counter. */
|
||||
dtv = &newp[1];
|
||||
|
||||
/* Install this new dtv in the thread data
|
||||
structures. */
|
||||
INSTALL_NEW_DTV (dtv);
|
||||
}
|
||||
|
||||
/* If there is currently memory allocate for this
|
||||
dtv entry free it. */
|
||||
/* XXX Ideally we will at some point create a memory
|
||||
pool. */
|
||||
if (dtv[modid].pointer != TLS_DTV_UNALLOCATED)
|
||||
/* Note that free is called for NULL is well. We
|
||||
deallocate even if it is this dtv entry we are
|
||||
supposed to load. The reason is that we call
|
||||
memalign and not malloc. */
|
||||
free (dtv[modid].pointer);
|
||||
|
||||
/* This module is loaded dynamically- We defer
|
||||
memory allocation. */
|
||||
dtv[modid].pointer = TLS_DTV_UNALLOCATED;
|
||||
|
||||
if (modid == GET_ADDR_MODULE)
|
||||
the_map = map;
|
||||
}
|
||||
|
||||
total += listp->len;
|
||||
}
|
||||
while ((listp = listp->next) != NULL);
|
||||
|
||||
/* This will be the new maximum generation counter. */
|
||||
dtv[0].counter = new_gen;
|
||||
}
|
||||
}
|
||||
|
||||
p = dtv[GET_ADDR_MODULE].pointer;
|
||||
p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||
|
||||
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
|
||||
{
|
||||
@ -703,11 +726,74 @@ __tls_get_addr (GET_ADDR_ARGS)
|
||||
the_map = listp->slotinfo[idx].map;
|
||||
}
|
||||
|
||||
p = dtv[GET_ADDR_MODULE].pointer = allocate_and_init (the_map);
|
||||
p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
||||
dtv[GET_ADDR_MODULE].pointer.is_static = false;
|
||||
}
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
# endif
|
||||
|
||||
|
||||
|
||||
void
|
||||
_dl_add_to_slotinfo (struct link_map *l)
|
||||
{
|
||||
/* Now that we know the object is loaded successfully add
|
||||
modules containing TLS data to the dtv info table. We
|
||||
might have to increase its size. */
|
||||
struct dtv_slotinfo_list *listp;
|
||||
struct dtv_slotinfo_list *prevp;
|
||||
size_t idx = l->l_tls_modid;
|
||||
|
||||
/* Find the place in the dtv slotinfo list. */
|
||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||
prevp = NULL; /* Needed to shut up gcc. */
|
||||
do
|
||||
{
|
||||
/* Does it fit in the array of this list element? */
|
||||
if (idx < listp->len)
|
||||
break;
|
||||
idx -= listp->len;
|
||||
prevp = listp;
|
||||
listp = listp->next;
|
||||
}
|
||||
while (listp != NULL);
|
||||
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* When we come here it means we have to add a new element
|
||||
to the slotinfo list. And the new module must be in
|
||||
the first slot. */
|
||||
assert (idx == 0);
|
||||
|
||||
listp = prevp->next = (struct dtv_slotinfo_list *)
|
||||
malloc (sizeof (struct dtv_slotinfo_list)
|
||||
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
if (listp == NULL)
|
||||
{
|
||||
/* We ran out of memory. We will simply fail this
|
||||
call but don't undo anything we did so far. The
|
||||
application will crash or be terminated anyway very
|
||||
soon. */
|
||||
|
||||
/* We have to do this since some entries in the dtv
|
||||
slotinfo array might already point to this
|
||||
generation. */
|
||||
++GL(dl_tls_generation);
|
||||
|
||||
_dl_signal_error (ENOMEM, "dlopen", NULL, N_("\
|
||||
cannot create TLS data structures"));
|
||||
}
|
||||
|
||||
listp->len = TLS_SLOTINFO_SURPLUS;
|
||||
listp->next = NULL;
|
||||
memset (listp->slotinfo, '\0',
|
||||
TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
|
||||
}
|
||||
|
||||
/* Add the information into the slotinfo data structure. */
|
||||
listp->slotinfo[idx].map = l;
|
||||
listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
|
||||
}
|
||||
#endif /* use TLS */
|
||||
|
1
sysdeps/generic/dl-trampoline.c
Normal file
1
sysdeps/generic/dl-trampoline.c
Normal file
@ -0,0 +1 @@
|
||||
#error "Architecture specific PLT trampolines must be defined."
|
@ -52,23 +52,15 @@ __BEGIN_DECLS
|
||||
most architectures the entry is already relocated - but for some not
|
||||
and we need to relocate at access time. */
|
||||
#ifdef DL_RO_DYN_SECTION
|
||||
# define D_PTR(map,i) (map->i->d_un.d_ptr + map->l_addr)
|
||||
# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr)
|
||||
#else
|
||||
# define D_PTR(map,i) map->i->d_un.d_ptr
|
||||
# define D_PTR(map, i) (map)->i->d_un.d_ptr
|
||||
#endif
|
||||
|
||||
/* On some platforms more information than just the address of the symbol
|
||||
is needed from the lookup functions. In this case we return the whole
|
||||
link map. */
|
||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
||||
/* Result of the lookup functions and how to retrieve the base address. */
|
||||
typedef struct link_map *lookup_t;
|
||||
# define LOOKUP_VALUE(map) map
|
||||
# define LOOKUP_VALUE_ADDRESS(map) (map ? map->l_addr : 0)
|
||||
#else
|
||||
typedef ElfW(Addr) lookup_t;
|
||||
# define LOOKUP_VALUE(map) map->l_addr
|
||||
# define LOOKUP_VALUE_ADDRESS(address) address
|
||||
#endif
|
||||
# define LOOKUP_VALUE_ADDRESS(map) ((map) ? (map)->l_addr : 0)
|
||||
|
||||
/* on some architectures a pointer to a function is not just a pointer
|
||||
to the actual code of the function but rather an architecture
|
||||
@ -182,6 +174,55 @@ enum allowmask
|
||||
};
|
||||
|
||||
|
||||
/* Type for list of auditing interfaces. */
|
||||
struct La_i86_regs;
|
||||
struct La_i86_retval;
|
||||
struct La_x86_64_regs;
|
||||
struct La_x86_64_retval;
|
||||
|
||||
|
||||
struct audit_ifaces
|
||||
{
|
||||
void (*activity) (uintptr_t *, unsigned int);
|
||||
char *(*objsearch) (const char *, uintptr_t *, unsigned int);
|
||||
unsigned int (*objopen) (struct link_map *, Lmid_t, uintptr_t *);
|
||||
void (*preinit) (uintptr_t *);
|
||||
union
|
||||
{
|
||||
uintptr_t (*symbind32) (Elf32_Sym *, unsigned int, uintptr_t *,
|
||||
uintptr_t *, unsigned int *, const char *);
|
||||
uintptr_t (*symbind64) (Elf64_Sym *, unsigned int, uintptr_t *,
|
||||
uintptr_t *, unsigned int *, const char *);
|
||||
};
|
||||
union
|
||||
{
|
||||
uintptr_t (*i86_gnu_pltenter) (Elf32_Sym *, unsigned int, uintptr_t *,
|
||||
uintptr_t *, const struct La_i86_regs *,
|
||||
unsigned int *, const char *name,
|
||||
long int *framesizep);
|
||||
uintptr_t (*x86_64_gnu_pltenter) (Elf64_Sym *, unsigned int, uintptr_t *,
|
||||
uintptr_t *,
|
||||
const struct La_x86_64_regs *,
|
||||
unsigned int *, const char *name,
|
||||
long int *framesizep);
|
||||
};
|
||||
union
|
||||
{
|
||||
unsigned int (*i86_gnu_pltexit) (Elf32_Sym *, unsigned int, uintptr_t *,
|
||||
uintptr_t *, const struct La_i86_regs *,
|
||||
struct La_i86_retval *, const char *);
|
||||
unsigned int (*x86_64_gnu_pltexit) (Elf64_Sym *, unsigned int, uintptr_t *,
|
||||
uintptr_t *,
|
||||
const struct La_x86_64_regs *,
|
||||
struct La_x86_64_retval *,
|
||||
const char *);
|
||||
};
|
||||
unsigned int (*objclose) (uintptr_t *);
|
||||
|
||||
struct audit_ifaces *next;
|
||||
};
|
||||
|
||||
|
||||
/* Test whether given NAME matches any of the names of the given object. */
|
||||
extern int _dl_name_match_p (const char *__name, struct link_map *__map)
|
||||
internal_function;
|
||||
@ -224,7 +265,7 @@ struct rtld_global
|
||||
#endif
|
||||
EXTERN struct link_namespaces
|
||||
{
|
||||
/* And a pointer to the map for the main map. */
|
||||
/* A pointer to the map for the main map. */
|
||||
struct link_map *_ns_loaded;
|
||||
/* Number of object in the _dl_loaded list. */
|
||||
unsigned int _ns_nloaded;
|
||||
@ -277,8 +318,12 @@ struct rtld_global
|
||||
EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
|
||||
#endif
|
||||
|
||||
/* Structure describing the dynamic linker itself. */
|
||||
/* Structure describing the dynamic linker itself. We need to
|
||||
reserve memory for the data the audit libraries need. */
|
||||
EXTERN struct link_map _dl_rtld_map;
|
||||
#ifdef SHARED
|
||||
struct auditstate audit_data[DL_NNS];
|
||||
#endif
|
||||
|
||||
#if defined SHARED && defined _LIBC_REENTRANT \
|
||||
&& defined __rtld_lock_default_lock_recursive
|
||||
@ -311,6 +356,7 @@ struct rtld_global
|
||||
struct dtv_slotinfo
|
||||
{
|
||||
size_t gen;
|
||||
bool is_static;
|
||||
struct link_map *map;
|
||||
} slotinfo[0];
|
||||
} *_dl_tls_dtv_slotinfo_list;
|
||||
@ -483,32 +529,12 @@ struct rtld_global_ro
|
||||
call the function instead of going through the PLT. The result
|
||||
is that we can avoid exporting the functions and we do not jump
|
||||
PLT relocations in libc.so. */
|
||||
const char *(*_dl_get_origin) (void);
|
||||
size_t (*_dl_dst_count) (const char *, int);
|
||||
char *(*_dl_dst_substitute) (struct link_map *, const char *, char *, int);
|
||||
struct link_map *(internal_function *_dl_map_object) (struct link_map *,
|
||||
const char *, int,
|
||||
int, int, int, Lmid_t);
|
||||
void (internal_function *_dl_map_object_deps) (struct link_map *,
|
||||
struct link_map **,
|
||||
unsigned int, int, int);
|
||||
void (*_dl_relocate_object) (struct link_map *, struct r_scope_elem *[],
|
||||
int, int);
|
||||
int (internal_function *_dl_check_map_versions) (struct link_map *, int,
|
||||
int);
|
||||
void (internal_function *_dl_init) (struct link_map *, int, char **,
|
||||
char **);
|
||||
void (*_dl_debug_state) (void);
|
||||
#ifndef MAP_COPY
|
||||
void (*_dl_unload_cache) (void);
|
||||
#endif
|
||||
void (*_dl_debug_printf) (const char *, ...)
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
int (internal_function *_dl_catch_error) (const char **, const char **,
|
||||
void (*) (void *), void *);
|
||||
void (internal_function *_dl_signal_error) (int, const char *, const char *,
|
||||
const char *);
|
||||
void (internal_function *_dl_start_profile) (void);
|
||||
void (*_dl_mcount) (ElfW(Addr) frompc, ElfW(Addr) selfpc);
|
||||
lookup_t (internal_function *_dl_lookup_symbol_x) (const char *,
|
||||
struct link_map *,
|
||||
@ -518,7 +544,13 @@ struct rtld_global_ro
|
||||
int, int,
|
||||
struct link_map *);
|
||||
int (*_dl_check_caller) (const void *, enum allowmask);
|
||||
void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen,
|
||||
Lmid_t nsid, int argc, char *argv[], char *env[]);
|
||||
void (*_dl_close) (void *map);
|
||||
|
||||
/* List of auditing interfaces. */
|
||||
struct audit_ifaces *_dl_audit;
|
||||
unsigned int _dl_naudit;
|
||||
};
|
||||
# define __rtld_global_attribute__
|
||||
# ifdef IS_IN_rtld
|
||||
@ -911,6 +943,20 @@ extern char *_dl_dst_substitute (struct link_map *l, const char *name,
|
||||
extern int _dl_check_caller (const void *caller, enum allowmask mask)
|
||||
attribute_hidden;
|
||||
|
||||
/* Open the shared object NAME, relocate it, and run its initializer if it
|
||||
hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If
|
||||
the object is already opened, returns its existing map. */
|
||||
extern void *_dl_open (const char *name, int mode, const void *caller,
|
||||
Lmid_t nsid, int argc, char *argv[], char *env[])
|
||||
attribute_hidden;
|
||||
|
||||
/* Add module to slot information data. */
|
||||
extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden;
|
||||
|
||||
/* Update slot information data for at least the generation of the
|
||||
module with the given index. */
|
||||
extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ldsodefs.h */
|
||||
|
@ -80,6 +80,10 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
||||
void *__unbounded stack_end)
|
||||
__attribute__ ((noreturn));
|
||||
|
||||
|
||||
/* Note: the fini parameter is ignored here. It used to be 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,
|
||||
@ -158,10 +162,6 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
__libc_init_first (argc, argv, __environ);
|
||||
#endif
|
||||
|
||||
/* Register the destructor of the program, if any. */
|
||||
if (fini)
|
||||
__cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
|
||||
|
||||
#ifndef SHARED
|
||||
/* Some security at this point. Prevent starting a SUID binary where
|
||||
the standard file descriptors are not opened. We have to do this
|
||||
@ -183,6 +183,22 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
#endif
|
||||
);
|
||||
|
||||
#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]);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Initialization code for TLS in statically linked application.
|
||||
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 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
|
||||
@ -178,17 +178,18 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
|
||||
|
||||
/* Initialize the TLS block. */
|
||||
# if TLS_TCB_AT_TP
|
||||
static_dtv[2].pointer = ((char *) tlsblock + tcb_offset
|
||||
- roundup (memsz, align ?: 1));
|
||||
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 = (char *) tlsblock + tcb_offset;
|
||||
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, initimage, filesz);
|
||||
memcpy (static_dtv[2].pointer.val, initimage, filesz);
|
||||
|
||||
/* Install the pointer to the dtv. */
|
||||
|
||||
|
@ -2,18 +2,19 @@
|
||||
all stuffed in a single string which means they have to be terminated
|
||||
with a '\0' explicitly. */
|
||||
#define UNSECURE_ENVVARS \
|
||||
"LD_PRELOAD\0" \
|
||||
"LD_LIBRARY_PATH\0" \
|
||||
"LD_ORIGIN_PATH\0" \
|
||||
"LD_DEBUG\0" \
|
||||
"LD_DEBUG_OUTPUT\0" \
|
||||
"LD_PROFILE\0" \
|
||||
"LD_USE_LOAD_BIAS\0" \
|
||||
"LD_DYNAMIC_WEAK\0" \
|
||||
"LD_SHOW_AUXV\0" \
|
||||
"GCONV_PATH\0" \
|
||||
"GETCONF_DIR\0" \
|
||||
"HOSTALIASES\0" \
|
||||
"LD_AUDIT\0" \
|
||||
"LD_DEBUG\0" \
|
||||
"LD_DEBUG_OUTPUT\0" \
|
||||
"LD_DYNAMIC_WEAK\0" \
|
||||
"LD_LIBRARY_PATH\0" \
|
||||
"LD_ORIGIN_PATH\0" \
|
||||
"LD_PRELOAD\0" \
|
||||
"LD_PROFILE\0" \
|
||||
"LD_SHOW_AUXV\0" \
|
||||
"LD_USE_LOAD_BIAS\0" \
|
||||
"LOCALDOMAIN\0" \
|
||||
"LOCPATH\0" \
|
||||
"MALLOC_TRACE\0" \
|
||||
|
@ -1,6 +0,0 @@
|
||||
/* Used to store the function descriptor table */
|
||||
struct link_map_machine
|
||||
{
|
||||
size_t fptr_table_len;
|
||||
ElfW(Addr) *fptr_table;
|
||||
};
|
6
sysdeps/hppa/bits/linkmap.h
Normal file
6
sysdeps/hppa/bits/linkmap.h
Normal file
@ -0,0 +1,6 @@
|
||||
/* Used to store the function descriptor table */
|
||||
struct link_map_machine
|
||||
{
|
||||
size_t fptr_table_len;
|
||||
ElfW(Addr) *fptr_table;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/* Configuration of lookup functions.
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 2000, 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
|
||||
@ -17,9 +17,6 @@
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
/* Like IA-64, PA-RISC needs more information from the symbol lookup
|
||||
function than just the address. */
|
||||
#define DL_LOOKUP_RETURNS_MAP
|
||||
#define ELF_FUNCTION_PTR_IS_SPECIAL
|
||||
#define DL_UNMAP_IS_SPECIAL
|
||||
|
||||
@ -66,4 +63,3 @@ void _dl_unmap (struct link_map *map);
|
||||
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))
|
||||
#define DL_DT_FINI_ADDRESS(map, addr) \
|
||||
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))
|
||||
|
||||
|
@ -1,5 +1,60 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 0x16 */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
||||
/* Copyright (C) 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. */
|
||||
|
||||
#ifndef _LINK_H
|
||||
# error "Never include <bits/link.h> directly; use <link.h> instead."
|
||||
#endif
|
||||
|
||||
|
||||
/* Registers for entry into PLT on IA-32. */
|
||||
typedef struct La_i86_regs
|
||||
{
|
||||
uint32_t lr_edx;
|
||||
uint32_t lr_ecx;
|
||||
uint32_t lr_eax;
|
||||
uint32_t lr_ebp;
|
||||
uint32_t lr_esp;
|
||||
} La_i86_regs;
|
||||
|
||||
/* Return values for calls from PLT on IA-32. */
|
||||
typedef struct La_i86_retval
|
||||
{
|
||||
uint32_t lrv_eax;
|
||||
uint32_t lrv_edx;
|
||||
long double lrv_st0;
|
||||
long double lrv_st1;
|
||||
} La_i86_retval;
|
||||
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern Elf32_Addr la_i86_gnu_pltenter (Elf32_Sym *__sym, unsigned int __ndx,
|
||||
uintptr_t *__refcook,
|
||||
uintptr_t *__defcook,
|
||||
La_i86_regs *__regs,
|
||||
unsigned int *__flags,
|
||||
const char *__symname,
|
||||
long int *__framesizep);
|
||||
extern unsigned int la_i86_gnu_pltexit (Elf32_Sym *__sym, unsigned int __ndx,
|
||||
uintptr_t *__refcook,
|
||||
uintptr_t *__defcook,
|
||||
const La_i86_regs *__inregs,
|
||||
La_i86_retval *__outregs,
|
||||
const char *symname);
|
||||
|
||||
__END_DECLS
|
||||
|
5
sysdeps/i386/bits/linkmap.h
Normal file
5
sysdeps/i386/bits/linkmap.h
Normal file
@ -0,0 +1,5 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 0x16 */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
@ -129,7 +129,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
{
|
||||
got[2] = (Elf32_Addr) &_dl_runtime_profile;
|
||||
|
||||
if (_dl_name_match_p (GLRO(dl_profile), l))
|
||||
if (GLRO(dl_profile) != NULL
|
||||
&& _dl_name_match_p (GLRO(dl_profile), l))
|
||||
/* This is the object we are looking for. Say that we really
|
||||
want profiling and the timers are started. */
|
||||
GL(dl_profile_map) = l;
|
||||
@ -154,112 +155,18 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
destroys the passed register information. */
|
||||
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
||||
without the `__unbounded' qualifier. */
|
||||
#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), unused))
|
||||
#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
|
||||
|
||||
static ElfW(Addr) fixup (struct link_map *__unbounded l,
|
||||
ElfW(Word) reloc_offset)
|
||||
extern ElfW(Addr) _dl_fixup (struct link_map *__unbounded l,
|
||||
ElfW(Word) reloc_offset)
|
||||
ARCH_FIXUP_ATTRIBUTE;
|
||||
static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset,
|
||||
ElfW(Addr) retaddr)
|
||||
extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
|
||||
ElfW(Word) reloc_offset,
|
||||
ElfW(Addr) retaddr, const void *regs,
|
||||
long int *framesizep)
|
||||
ARCH_FIXUP_ATTRIBUTE;
|
||||
# endif
|
||||
|
||||
/* This code is used in dl-runtime.c to call the `fixup' function
|
||||
and then redirect to the address it returns. */
|
||||
# if !defined PROF && !__BOUNDED_POINTERS__
|
||||
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
|
||||
.text\n\
|
||||
.globl _dl_runtime_resolve\n\
|
||||
.type _dl_runtime_resolve, @function\n\
|
||||
" CFI_STARTPROC "\n\
|
||||
.align 16\n\
|
||||
_dl_runtime_resolve:\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (8) "\n\
|
||||
pushl %eax # Preserve registers otherwise clobbered.\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %edx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\
|
||||
movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\
|
||||
call fixup # Call resolver.\n\
|
||||
popl %edx # Get register content back.\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
popl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
|
||||
ret $8 # Jump to function address.\n\
|
||||
" CFI_ENDPROC "\n\
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
|
||||
\n\
|
||||
.globl _dl_runtime_profile\n\
|
||||
.type _dl_runtime_profile, @function\n\
|
||||
" CFI_STARTPROC "\n\
|
||||
.align 16\n\
|
||||
_dl_runtime_profile:\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (8) "\n\
|
||||
pushl %eax # Preserve registers otherwise clobbered.\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %edx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
movl 20(%esp), %ecx # Load return address\n\
|
||||
movl 16(%esp), %edx # Copy args pushed by PLT in register. Note\n\
|
||||
movl 12(%esp), %eax # that `fixup' takes its parameters in regs.\n\
|
||||
call profile_fixup # Call resolver.\n\
|
||||
popl %edx # Get register content back.\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
popl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
|
||||
ret $8 # Jump to function address.\n\
|
||||
" CFI_ENDPROC "\n\
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
|
||||
.previous\n\
|
||||
");
|
||||
# else
|
||||
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
|
||||
.text\n\
|
||||
.globl _dl_runtime_resolve\n\
|
||||
.globl _dl_runtime_profile\n\
|
||||
.type _dl_runtime_resolve, @function\n\
|
||||
.type _dl_runtime_profile, @function\n\
|
||||
" CFI_STARTPROC "\n\
|
||||
.align 16\n\
|
||||
_dl_runtime_resolve:\n\
|
||||
_dl_runtime_profile:\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (8) "\n\
|
||||
pushl %eax # Preserve registers otherwise clobbered.\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %edx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
movl 16(%esp), %edx # Push the arguments for `fixup'\n\
|
||||
movl 12(%esp), %eax\n\
|
||||
pushl %edx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
pushl %eax\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (4) "\n\
|
||||
call fixup # Call resolver.\n\
|
||||
popl %edx # Pop the parameters\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
popl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
popl %edx # Get register content back.\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
popl %ecx\n\
|
||||
" CFI_ADJUST_CFA_OFFSET (-4) "\n\
|
||||
xchgl %eax, (%esp) # Get %eax contents end store function address.\n\
|
||||
ret $8 # Jump to function address.\n\
|
||||
" CFI_ENDPROC "\n\
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
|
||||
.previous\n\
|
||||
");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Mask identifying addresses reserved for the user program,
|
||||
@ -375,9 +282,14 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/* Names of the architecture-specific auditing callback functions. */
|
||||
#define ARCH_LA_PLTENTER i86_gnu_pltenter
|
||||
#define ARCH_LA_PLTEXIT i86_gnu_pltexit
|
||||
|
||||
#endif /* !dl_machine_h */
|
||||
|
||||
#ifdef RESOLVE
|
||||
#ifdef RESOLVE_MAP
|
||||
|
||||
/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
|
||||
Prelinked libraries may use Elf32_Rela though. */
|
||||
@ -422,7 +334,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
||||
#endif /* !RTLD_BOOTSTRAP and have no -z combreloc */
|
||||
{
|
||||
const Elf32_Sym *const refsym = sym;
|
||||
#if defined USE_TLS && !defined RTLD_BOOTSTRAP
|
||||
#ifndef RTLD_BOOTSTRAP
|
||||
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
||||
#else
|
||||
@ -549,14 +461,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
|
||||
# ifndef RESOLVE_CONFLICT_FIND_MAP
|
||||
const Elf32_Sym *const refsym = sym;
|
||||
# endif
|
||||
# ifdef USE_TLS
|
||||
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
||||
# else
|
||||
Elf32_Addr value = RESOLVE (&sym, version, r_type);
|
||||
if (sym != NULL)
|
||||
value += sym->st_value;
|
||||
# endif
|
||||
|
||||
switch (ELF32_R_TYPE (reloc->r_info))
|
||||
{
|
||||
@ -692,4 +598,4 @@ elf_machine_lazy_rela (struct link_map *map,
|
||||
|
||||
#endif /* !RTLD_BOOTSTRAP */
|
||||
|
||||
#endif /* RESOLVE */
|
||||
#endif /* RESOLVE_MAP */
|
||||
|
182
sysdeps/i386/dl-trampoline.S
Normal file
182
sysdeps/i386/dl-trampoline.S
Normal file
@ -0,0 +1,182 @@
|
||||
/* PLT trampolines. i386 version.
|
||||
Copyright (C) 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 <sysdep.h>
|
||||
|
||||
.text
|
||||
.globl _dl_runtime_resolve
|
||||
.type _dl_runtime_resolve, @function
|
||||
cfi_startproc
|
||||
.align 16
|
||||
_dl_runtime_resolve:
|
||||
cfi_adjust_cfa_offset (8)
|
||||
pushl %eax # Preserve registers otherwise clobbered.
|
||||
cfi_adjust_cfa_offset (4)
|
||||
pushl %ecx
|
||||
cfi_adjust_cfa_offset (4)
|
||||
pushl %edx
|
||||
cfi_adjust_cfa_offset (4)
|
||||
movl 16(%esp), %edx # Copy args pushed by PLT in register. Note
|
||||
movl 12(%esp), %eax # that `fixup' takes its parameters in regs.
|
||||
call _dl_fixup # Call resolver.
|
||||
popl %edx # Get register content back.
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
popl %ecx
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
xchgl %eax, (%esp) # Get %eax contents end store function address.
|
||||
ret $8 # Jump to function address.
|
||||
cfi_endproc
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve
|
||||
|
||||
|
||||
.globl _dl_runtime_profile
|
||||
.type _dl_runtime_profile, @function
|
||||
cfi_startproc
|
||||
.align 16
|
||||
_dl_runtime_profile:
|
||||
cfi_adjust_cfa_offset (8)
|
||||
pushl %esp
|
||||
cfi_adjust_cfa_offset (4)
|
||||
addl $8, (%esp) # Account for the pushed PLT data
|
||||
pushl %ebp
|
||||
cfi_adjust_cfa_offset (4)
|
||||
pushl %eax # Preserve registers otherwise clobbered.
|
||||
cfi_adjust_cfa_offset (4)
|
||||
pushl %ecx
|
||||
cfi_adjust_cfa_offset (4)
|
||||
pushl %edx
|
||||
cfi_adjust_cfa_offset (4)
|
||||
movl %esp, %ecx
|
||||
subl $8, %esp
|
||||
cfi_adjust_cfa_offset (8)
|
||||
movl $-1, 4(%esp)
|
||||
leal 4(%esp), %edx
|
||||
movl %edx, (%esp)
|
||||
pushl %ecx # Address of the register structure
|
||||
cfi_adjust_cfa_offset (4)
|
||||
movl 40(%esp), %ecx # Load return address
|
||||
movl 36(%esp), %edx # Copy args pushed by PLT in register. Note
|
||||
movl 32(%esp), %eax # that `fixup' takes its parameters in regs.
|
||||
call _dl_profile_fixup # Call resolver.
|
||||
cfi_adjust_cfa_offset (-8)
|
||||
movl (%esp), %edx
|
||||
testl %edx, %edx
|
||||
jns 1f
|
||||
popl %edx
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
popl %edx # Get register content back.
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
popl %ecx
|
||||
cfi_adjust_cfa_offset (-4)
|
||||
xchgl %eax, (%esp) # Get %eax contents end store function address.
|
||||
ret $16 # Jump to function address.
|
||||
|
||||
/*
|
||||
+32 return address
|
||||
+28 PLT1
|
||||
+24 PLT2
|
||||
+20 %esp
|
||||
+16 %ebp
|
||||
+12 %eax
|
||||
+8 %ecx
|
||||
+4 %edx
|
||||
%esp free
|
||||
*/
|
||||
cfi_adjust_cfa_offset (12)
|
||||
1: movl %ebx, (%esp)
|
||||
cfi_rel_offset (3, 0)
|
||||
movl %edx, %ebx # This is the frame buffer size
|
||||
pushl %edi
|
||||
cfi_adjust_cfa_offset (4)
|
||||
cfi_rel_offset (7, 0)
|
||||
pushl %esi
|
||||
cfi_adjust_cfa_offset (4)
|
||||
cfi_rel_offset (6, 0)
|
||||
leal 44(%esp), %esi
|
||||
movl %ebx, %ecx
|
||||
movl %esp, %edi
|
||||
subl %ebx, %edi
|
||||
andl $0xfffffff0, %edi # Align stack
|
||||
movl %esp, %ebx
|
||||
cfi_def_cfa_register (3)
|
||||
movl %edi, %esp
|
||||
shrl $2, %ecx
|
||||
rep
|
||||
movsl
|
||||
movl (%edi), %esi
|
||||
cfi_restore (6)
|
||||
movl 4(%edi), %edi
|
||||
cfi_restore (7)
|
||||
/*
|
||||
%ebx+40 return address
|
||||
%ebx+36 PLT1
|
||||
%ebx+32 PLT2
|
||||
%ebx+28 %esp
|
||||
%ebx+24 %ebp
|
||||
%ebx+20 %eax
|
||||
%ebx+16 %ecx
|
||||
%ebx+12 %edx
|
||||
%ebx+8 %ebx
|
||||
%ebx+4 free
|
||||
%ebx free
|
||||
%esp copied stack frame
|
||||
*/
|
||||
movl %eax, (%ebx)
|
||||
movl 12(%ebx), %edx
|
||||
movl 16(%ebx), %ecx
|
||||
movl 20(%ebx), %eax
|
||||
call *(%ebx)
|
||||
movl %ebx, %esp
|
||||
cfi_def_cfa_register (4)
|
||||
movl 8(%esp), %ebx
|
||||
cfi_restore (3)
|
||||
/*
|
||||
+40 return address
|
||||
+36 PLT1
|
||||
+32 PLT2
|
||||
+28 %esp
|
||||
+24 %ebp
|
||||
+20 %eax
|
||||
+16 %ecx
|
||||
+12 %edx
|
||||
+8 free
|
||||
+4 free
|
||||
%esp free
|
||||
*/
|
||||
subl $20, %esp
|
||||
cfi_adjust_cfa_offset (20)
|
||||
movl %eax, (%esp)
|
||||
movl %edx, 4(%esp)
|
||||
fstpt 8(%esp)
|
||||
fstpt 20(%esp)
|
||||
pushl %esp
|
||||
cfi_adjust_cfa_offset (4)
|
||||
leal 36(%esp), %ecx
|
||||
movl 56(%esp), %eax
|
||||
movl 60(%esp), %edx
|
||||
call _dl_call_pltexit
|
||||
movl (%esp), %eax
|
||||
movl 4(%esp), %edx
|
||||
fldt 20(%esp)
|
||||
fldt 8(%esp)
|
||||
addl $60, %esp
|
||||
cfi_adjust_cfa_offset (-60)
|
||||
ret
|
||||
cfi_endproc
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile
|
@ -1,5 +0,0 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
size_t fptr_table_len;
|
||||
Elf64_Addr *fptr_table;
|
||||
};
|
5
sysdeps/ia64/bits/linkmap.h
Normal file
5
sysdeps/ia64/bits/linkmap.h
Normal file
@ -0,0 +1,5 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
size_t fptr_table_len;
|
||||
Elf64_Addr *fptr_table;
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/* Configuration of lookup functions.
|
||||
Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
|
||||
Copyright (C) 2000, 2001, 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
|
||||
@ -17,9 +17,6 @@
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
/* The ia64 need more information from the symbol lookup function
|
||||
than just the address. */
|
||||
#define DL_LOOKUP_RETURNS_MAP
|
||||
#define ELF_FUNCTION_PTR_IS_SPECIAL
|
||||
#define DL_UNMAP_IS_SPECIAL
|
||||
|
||||
|
4
sysdeps/linkmap.h
Normal file
4
sysdeps/linkmap.h
Normal file
@ -0,0 +1,4 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
/* empty by default */
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
/* Configuration of lookup functions. PowerPC64 version.
|
||||
Copyright (C) 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. */
|
||||
|
||||
/* Return the symbol map from the symbol lookup function. */
|
||||
|
||||
#define DL_LOOKUP_RETURNS_MAP 1
|
@ -1,13 +0,0 @@
|
||||
#if __WORDSIZE == 64
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf64_Addr plt; /* Address of .plt + 0x2e */
|
||||
Elf64_Addr gotplt; /* Address of .got + 0x18 */
|
||||
};
|
||||
#else
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 0x2c */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
||||
#endif
|
13
sysdeps/s390/bits/linkmap.h
Normal file
13
sysdeps/s390/bits/linkmap.h
Normal file
@ -0,0 +1,13 @@
|
||||
#if __WORDSIZE == 64
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf64_Addr plt; /* Address of .plt + 0x2e */
|
||||
Elf64_Addr gotplt; /* Address of .got + 0x18 */
|
||||
};
|
||||
#else
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 0x2c */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
||||
#endif
|
@ -1,5 +0,0 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 36 */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
5
sysdeps/sh/bits/linkmap.h
Normal file
5
sysdeps/sh/bits/linkmap.h
Normal file
@ -0,0 +1,5 @@
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 36 */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
@ -1,14 +1,112 @@
|
||||
#if __WORDSIZE == 64
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf64_Addr plt; /* Address of .plt + 0x16 */
|
||||
Elf64_Addr gotplt; /* Address of .got + 0x18 */
|
||||
};
|
||||
/* Copyright (C) 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. */
|
||||
|
||||
#ifndef _LINK_H
|
||||
# error "Never include <bits/link.h> directly; use <link.h> instead."
|
||||
#endif
|
||||
|
||||
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
/* Registers for entry into PLT on IA-32. */
|
||||
typedef struct La_i86_regs
|
||||
{
|
||||
uint32_t lr_edx;
|
||||
uint32_t lr_ecx;
|
||||
uint32_t lr_eax;
|
||||
uint32_t lr_ebp;
|
||||
uint32_t lr_esp;
|
||||
} La_i86_regs;
|
||||
|
||||
/* Return values for calls from PLT on IA-32. */
|
||||
typedef struct La_i86_retval
|
||||
{
|
||||
uint32_t lrv_eax;
|
||||
uint32_t lrv_edx;
|
||||
long double lrv_st0;
|
||||
long double lrv_st1;
|
||||
} La_i86_retval;
|
||||
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern Elf32_Addr la_i86_gnu_pltenter (Elf32_Sym *__sym, unsigned int __ndx,
|
||||
uintptr_t *__refcook,
|
||||
uintptr_t *__defcook,
|
||||
La_i86_regs *__regs,
|
||||
unsigned int *__flags,
|
||||
const char *__symname,
|
||||
long int *__framesizep);
|
||||
extern unsigned int la_i86_gnu_pltexit (Elf32_Sym *__sym, unsigned int __ndx,
|
||||
uintptr_t *__refcook,
|
||||
uintptr_t *__defcook,
|
||||
const La_i86_regs *__inregs,
|
||||
La_i86_retval *__outregs,
|
||||
const char *symname);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#else
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 0x16 */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
||||
|
||||
/* Registers for entry into PLT on x86-64. */
|
||||
typedef float La_x86_64_xmm __attribute__ ((__mode__ (__V4SF__)));
|
||||
typedef struct La_x86_64_regs
|
||||
{
|
||||
uint64_t lr_rdx;
|
||||
uint64_t lr_r8;
|
||||
uint64_t lr_r9;
|
||||
uint64_t lr_rcx;
|
||||
uint64_t lr_rsi;
|
||||
uint64_t lr_rdi;
|
||||
uint64_t lr_rbp;
|
||||
uint64_t lr_rsp;
|
||||
La_x86_64_xmm lr_xmm[8];
|
||||
} La_x86_64_regs;
|
||||
|
||||
/* Return values for calls from PLT on x86-64. */
|
||||
typedef struct La_x86_64_retval
|
||||
{
|
||||
uint64_t lrv_rax;
|
||||
uint64_t lrv_rdx;
|
||||
La_x86_64_xmm lrv_xmm0;
|
||||
La_x86_64_xmm lrv_xmm1;
|
||||
long double lrv_st0;
|
||||
long double lrv_st1;
|
||||
} La_x86_64_retval;
|
||||
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern Elf64_Addr la_x86_64_gnu_pltenter (Elf64_Sym *__sym,
|
||||
unsigned int __ndx,
|
||||
uintptr_t *__refcook,
|
||||
uintptr_t *__defcook,
|
||||
La_x86_64_regs *__regs,
|
||||
unsigned int *__flags,
|
||||
const char *__symname,
|
||||
long int *__framesizep);
|
||||
extern unsigned int la_x86_64_gnu_pltexit (Elf64_Sym *__sym,
|
||||
unsigned int __ndx,
|
||||
uintptr_t *__refcook,
|
||||
uintptr_t *__defcook,
|
||||
const La_x86_64_regs *__inregs,
|
||||
La_x86_64_retval *__outregs,
|
||||
const char *symname);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
14
sysdeps/x86_64/bits/linkmap.h
Normal file
14
sysdeps/x86_64/bits/linkmap.h
Normal file
@ -0,0 +1,14 @@
|
||||
#if __WORDSIZE == 64
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf64_Addr plt; /* Address of .plt + 0x16 */
|
||||
Elf64_Addr gotplt; /* Address of .got + 0x18 */
|
||||
};
|
||||
|
||||
#else
|
||||
struct link_map_machine
|
||||
{
|
||||
Elf32_Addr plt; /* Address of .plt + 0x16 */
|
||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
||||
};
|
||||
#endif
|
@ -116,7 +116,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
{
|
||||
got[2] = (Elf64_Addr) &_dl_runtime_profile;
|
||||
|
||||
if (_dl_name_match_p (GLRO(dl_profile), l))
|
||||
if (GLRO(dl_profile) != NULL
|
||||
&& _dl_name_match_p (GLRO(dl_profile), l))
|
||||
/* This is the object we are looking for. Say that we really
|
||||
want profiling and the timers are started. */
|
||||
GL(dl_profile_map) = l;
|
||||
@ -130,128 +131,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||||
return lazy;
|
||||
}
|
||||
|
||||
/* This code is used in dl-runtime.c to call the `fixup' function
|
||||
and then redirect to the address it returns. */
|
||||
#ifndef PROF
|
||||
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
|
||||
.text\n\
|
||||
.globl _dl_runtime_resolve\n\
|
||||
.type _dl_runtime_resolve, @function\n\
|
||||
.align 16\n\
|
||||
" CFI_STARTPROC "\n\
|
||||
_dl_runtime_resolve:\n\
|
||||
subq $56,%rsp\n\
|
||||
" CFI_ADJUST_CFA_OFFSET(72)" # Incorporate PLT\n\
|
||||
movq %rax,(%rsp) # Preserve registers otherwise clobbered.\n\
|
||||
movq %rcx,8(%rsp)\n\
|
||||
movq %rdx,16(%rsp)\n\
|
||||
movq %rsi,24(%rsp)\n\
|
||||
movq %rdi,32(%rsp)\n\
|
||||
movq %r8,40(%rsp)\n\
|
||||
movq %r9,48(%rsp)\n\
|
||||
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.\n\
|
||||
movq %rsi,%r11 # Multiply by 24\n\
|
||||
addq %r11,%rsi\n\
|
||||
addq %r11,%rsi\n\
|
||||
shlq $3, %rsi\n\
|
||||
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset\n\
|
||||
call fixup # Call resolver.\n\
|
||||
movq %rax, %r11 # Save return value\n\
|
||||
movq 48(%rsp),%r9 # Get register content back.\n\
|
||||
movq 40(%rsp),%r8\n\
|
||||
movq 32(%rsp),%rdi\n\
|
||||
movq 24(%rsp),%rsi\n\
|
||||
movq 16(%rsp),%rdx\n\
|
||||
movq 8(%rsp),%rcx\n\
|
||||
movq (%rsp),%rax\n\
|
||||
addq $72,%rsp # Adjust stack(PLT did 2 pushes)\n\
|
||||
" CFI_ADJUST_CFA_OFFSET(-72)" \n\
|
||||
jmp *%r11 # Jump to function address.\n\
|
||||
" CFI_ENDPROC "\n\
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
|
||||
\n\
|
||||
.globl _dl_runtime_profile\n\
|
||||
.type _dl_runtime_profile, @function\n\
|
||||
.align 16\n\
|
||||
" CFI_STARTPROC "\n\
|
||||
_dl_runtime_profile:\n\
|
||||
subq $56,%rsp\n\
|
||||
" CFI_ADJUST_CFA_OFFSET(72)" # Incorporate PLT\n\
|
||||
movq %rax,(%rsp) # Preserve registers otherwise clobbered.\n\
|
||||
movq %rcx,8(%rsp)\n\
|
||||
movq %rdx,16(%rsp)\n\
|
||||
movq %rsi,24(%rsp)\n\
|
||||
movq %rdi,32(%rsp)\n\
|
||||
movq %r8,40(%rsp)\n\
|
||||
movq %r9,48(%rsp)\n\
|
||||
movq 72(%rsp), %rdx # Load return address if needed\n\
|
||||
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.\n\
|
||||
movq %rsi,%r11 # Multiply by 24\n\
|
||||
addq %r11,%rsi\n\
|
||||
addq %r11,%rsi\n\
|
||||
shlq $3, %rsi\n\
|
||||
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset\n\
|
||||
call profile_fixup # Call resolver.\n\
|
||||
movq %rax, %r11 # Save return value\n\
|
||||
movq 48(%rsp),%r9 # Get register content back.\n\
|
||||
movq 40(%rsp),%r8\n\
|
||||
movq 32(%rsp),%rdi\n\
|
||||
movq 24(%rsp),%rsi\n\
|
||||
movq 16(%rsp),%rdx\n\
|
||||
movq 8(%rsp),%rcx\n\
|
||||
movq (%rsp),%rax\n\
|
||||
addq $72,%rsp # Adjust stack\n\
|
||||
" CFI_ADJUST_CFA_OFFSET(-72)"\n\
|
||||
jmp *%r11 # Jump to function address.\n\
|
||||
" CFI_ENDPROC "\n\
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
|
||||
.previous\n\
|
||||
");
|
||||
#else
|
||||
# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
|
||||
.text\n\
|
||||
.globl _dl_runtime_resolve\n\
|
||||
.globl _dl_runtime_profile\n\
|
||||
.type _dl_runtime_resolve, @function\n\
|
||||
.type _dl_runtime_profile, @function\n\
|
||||
.align 16\n\
|
||||
" CFI_STARTPROC "\n\
|
||||
_dl_runtime_resolve:\n\
|
||||
_dl_runtime_profile:\n\
|
||||
subq $56,%rsp\n\
|
||||
" CFI_ADJUST_CFA_OFFSET(72)" # Incorporate PLT\n\
|
||||
movq %rax,(%rsp) # Preserve registers otherwise clobbered.\n\
|
||||
movq %rcx,8(%rsp)\n\
|
||||
movq %rdx,16(%rsp)\n\
|
||||
movq %rsi,24(%rsp)\n\
|
||||
movq %rdi,32(%rsp)\n\
|
||||
movq %r8,40(%rsp)\n\
|
||||
movq %r9,48(%rsp)\n\
|
||||
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.\n\
|
||||
movq %rsi,%r11 # Multiply by 24\n\
|
||||
addq %r11,%rsi\n\
|
||||
addq %r11,%rsi\n\
|
||||
shlq $3, %rsi\n\
|
||||
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset\n\
|
||||
call fixup # Call resolver.\n\
|
||||
movq %rax, %r11 # Save return value\n\
|
||||
movq 48(%rsp),%r9 # Get register content back.\n\
|
||||
movq 40(%rsp),%r8\n\
|
||||
movq 32(%rsp),%rdi\n\
|
||||
movq 24(%rsp),%rsi\n\
|
||||
movq 16(%rsp),%rdx\n\
|
||||
movq 8(%rsp),%rcx\n\
|
||||
movq (%rsp),%rax\n\
|
||||
addq $72,%rsp # Adjust stack\n\
|
||||
" CFI_ADJUST_CFA_OFFSET(-72)"\n\
|
||||
jmp *%r11 # Jump to function address.\n\
|
||||
" CFI_ENDPROC "\n\
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile\n\
|
||||
.previous\n\
|
||||
");
|
||||
#endif
|
||||
|
||||
/* Initial entry point code for the dynamic linker.
|
||||
The C function `_dl_start' is the real entry point;
|
||||
its return value is the user program's entry point. */
|
||||
@ -348,9 +227,14 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc,
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/* Names of the architecture-specific auditing callback functions. */
|
||||
#define ARCH_LA_PLTENTER x86_64_gnu_pltenter
|
||||
#define ARCH_LA_PLTEXIT x86_64_gnu_pltexit
|
||||
|
||||
#endif /* !dl_machine_h */
|
||||
|
||||
#ifdef RESOLVE
|
||||
#ifdef RESOLVE_MAP
|
||||
|
||||
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
|
||||
MAP is the object containing the reloc. */
|
||||
@ -390,7 +274,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
|
||||
#ifndef RTLD_BOOTSTRAP
|
||||
const Elf64_Sym *const refsym = sym;
|
||||
#endif
|
||||
#if defined USE_TLS && !defined RTLD_BOOTSTRAP
|
||||
#ifndef RTLD_BOOTSTRAP
|
||||
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||
Elf64_Addr value = (sym == NULL ? 0
|
||||
: (Elf64_Addr) sym_map->l_addr + sym->st_value);
|
||||
@ -553,4 +437,4 @@ elf_machine_lazy_rel (struct link_map *map,
|
||||
_dl_reloc_bad_type (map, r_type, 1);
|
||||
}
|
||||
|
||||
#endif /* RESOLVE */
|
||||
#endif /* RESOLVE_MAP */
|
||||
|
188
sysdeps/x86_64/dl-trampoline.S
Normal file
188
sysdeps/x86_64/dl-trampoline.S
Normal file
@ -0,0 +1,188 @@
|
||||
/* PLT trampolines. x86-64 version.
|
||||
Copyright (C) 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 <sysdep.h>
|
||||
|
||||
.text
|
||||
.globl _dl_runtime_resolve
|
||||
.type _dl_runtime_resolve, @function
|
||||
.align 16
|
||||
cfi_startproc
|
||||
_dl_runtime_resolve:
|
||||
subq $56,%rsp
|
||||
cfi_adjust_cfa_offset(72) # Incorporate PLT
|
||||
movq %rax,(%rsp) # Preserve registers otherwise clobbered.
|
||||
movq %rcx, 8(%rsp)
|
||||
movq %rdx, 16(%rsp)
|
||||
movq %rsi, 24(%rsp)
|
||||
movq %rdi, 32(%rsp)
|
||||
movq %r8, 40(%rsp)
|
||||
movq %r9, 48(%rsp)
|
||||
movq 64(%rsp), %rsi # Copy args pushed by PLT in register.
|
||||
movq %rsi, %r11 # Multiply by 24
|
||||
addq %r11, %rsi
|
||||
addq %r11, %rsi
|
||||
shlq $3, %rsi
|
||||
movq 56(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset
|
||||
call _dl_fixup # Call resolver.
|
||||
movq %rax, %r11 # Save return value
|
||||
movq 48(%rsp), %r9 # Get register content back.
|
||||
movq 40(%rsp), %r8
|
||||
movq 32(%rsp), %rdi
|
||||
movq 24(%rsp), %rsi
|
||||
movq 16(%rsp), %rdx
|
||||
movq 8(%rsp), %rcx
|
||||
movq (%rsp), %rax
|
||||
addq $72, %rsp # Adjust stack(PLT did 2 pushes)
|
||||
cfi_adjust_cfa_offset(-72)
|
||||
jmp *%r11 # Jump to function address.
|
||||
cfi_endproc
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve
|
||||
|
||||
|
||||
|
||||
.globl _dl_runtime_profile
|
||||
.type _dl_runtime_profile, @function
|
||||
.align 16
|
||||
cfi_startproc
|
||||
_dl_runtime_profile:
|
||||
subq $80, %rsp
|
||||
cfi_adjust_cfa_offset(96) # Incorporate PLT
|
||||
movq %rax, (%rsp) # Preserve registers otherwise clobbered.
|
||||
movq %rdx, 8(%rsp)
|
||||
movq %r8, 16(%rsp)
|
||||
movq %r9, 24(%rsp)
|
||||
movq %rcx, 32(%rsp)
|
||||
movq %rsi, 40(%rsp)
|
||||
movq %rdi, 48(%rsp)
|
||||
movq %rbp, 56(%rsp) # Information for auditors.
|
||||
leaq 96(%rsp), %rax
|
||||
movq %rax, 64(%rsp)
|
||||
leaq 8(%rsp), %rcx
|
||||
movq 96(%rsp), %rdx # Load return address if needed
|
||||
movq 88(%rsp), %rsi # Copy args pushed by PLT in register.
|
||||
movq %rsi,%r11 # Multiply by 24
|
||||
addq %r11,%rsi
|
||||
addq %r11,%rsi
|
||||
shlq $3, %rsi
|
||||
movq 80(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset
|
||||
leaq 72(%rsp), %r8
|
||||
call _dl_profile_fixup # Call resolver.
|
||||
movq %rax, %r11 # Save return value
|
||||
movq 8(%rsp), %rdx # Get back register content.
|
||||
movq 16(%rsp), %r8
|
||||
movq 24(%rsp), %r9
|
||||
movq (%rsp),%rax
|
||||
movq 72(%rsp), %r10
|
||||
testq %r10, %r10
|
||||
jns 1f
|
||||
movq 32(%rsp), %rcx
|
||||
movq 40(%rsp), %rsi
|
||||
movq 48(%rsp), %rdi
|
||||
addq $96,%rsp # Adjust stack
|
||||
cfi_adjust_cfa_offset (-96)
|
||||
jmp *%r11 # Jump to function address.
|
||||
|
||||
/*
|
||||
+96 return address
|
||||
+88 PLT2
|
||||
+80 PLT1
|
||||
+72 free
|
||||
+64 %rsp
|
||||
+56 %rbp
|
||||
+48 %rdi
|
||||
+40 %rsi
|
||||
+32 %rcx
|
||||
+24 %r9
|
||||
+16 %r8
|
||||
+8 %rdx
|
||||
%esp %rax
|
||||
*/
|
||||
cfi_adjust_cfa_offset (96)
|
||||
1: movq %rbx, 72(%rsp)
|
||||
cfi_rel_offset (1, 72)
|
||||
leaq 104(%rsp), %rsi
|
||||
movq %rsp, %rbx
|
||||
cfi_def_cfa_register (1)
|
||||
subq %r10, %rsp
|
||||
movq %rsp, %rdi
|
||||
movq %r10, %rcx
|
||||
shrq $3, %rcx
|
||||
rep
|
||||
movsq
|
||||
andq $0xfffffffffffffff0, %rsp
|
||||
movq 32(%rbx), %rcx
|
||||
movq 40(%rbx), %rsi
|
||||
movq 48(%rbx), %rdi
|
||||
call *%r11
|
||||
movq %rbx, %rsp
|
||||
cfi_def_cfa_register (7)
|
||||
subq $72, %rsp
|
||||
cfi_adjust_cfa_offset (72)
|
||||
movq %rsp, %rcx
|
||||
movq %rax, (%rcx)
|
||||
movq %rdx, 8(%rcx)
|
||||
/* Even though the stack is correctly aligned to allow using movaps
|
||||
we use movups. Some callers might provide an incorrectly aligned
|
||||
stack and we do not want to have it blow up here. */
|
||||
movups %xmm0, 16(%rcx)
|
||||
movups %xmm1, 32(%rcx)
|
||||
fstpt 48(%rcx)
|
||||
fstpt 64(%rcx)
|
||||
/*
|
||||
+168 return address
|
||||
+160 PLT2
|
||||
+152 PLT1
|
||||
+144 free
|
||||
+136 %rsp
|
||||
+128 %rbp
|
||||
+120 %rdi
|
||||
+112 %rsi
|
||||
+104 %rcx
|
||||
+96 %r9
|
||||
+88 %r8
|
||||
+80 %rdx
|
||||
+64 %st1 result
|
||||
+48 %st result
|
||||
+32 %xmm1 result
|
||||
+16 %xmm0 result
|
||||
+8 %rdx result
|
||||
%esp %rax result
|
||||
*/
|
||||
leaq 80(%rsp), %rdx
|
||||
movq 144(%rsp), %rbx
|
||||
cfi_restore (1)
|
||||
movq 160(%rsp), %rsi # Copy args pushed by PLT in register.
|
||||
movq %rsi,%r11 # Multiply by 24
|
||||
addq %r11,%rsi
|
||||
addq %r11,%rsi
|
||||
shlq $3, %rsi
|
||||
movq 152(%rsp), %rdi # %rdi: link_map, %rsi: reloc_offset
|
||||
call _dl_call_pltexit
|
||||
movq (%rsp), %rax
|
||||
movq 8(%rsp), %rdx
|
||||
movups 16(%rsp), %xmm0
|
||||
movups 32(%rsp), %xmm1
|
||||
fldt 64(%rsp)
|
||||
fldt 48(%rsp)
|
||||
addq $168, %rsp
|
||||
cfi_adjust_cfa_offset (-168)
|
||||
retq
|
||||
cfi_endproc
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile
|
Loading…
Reference in New Issue
Block a user