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
|
#error "Architecture-specific definition needed."
|
||||||
{
|
|
||||||
/* empty by default */
|
|
||||||
};
|
|
||||||
|
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.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -86,9 +86,13 @@ __libc_csu_init (void)
|
|||||||
#endif
|
#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
|
void
|
||||||
__libc_csu_fini (void)
|
__libc_csu_fini (void)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
#ifdef HAVE_INITFINI_ARRAY
|
#ifdef HAVE_INITFINI_ARRAY
|
||||||
size_t i = __fini_array_end - __fini_array_start;
|
size_t i = __fini_array_end - __fini_array_start;
|
||||||
while (i-- > 0)
|
while (i-- > 0)
|
||||||
@ -96,4 +100,5 @@ __libc_csu_fini (void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_fini ();
|
_fini ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ subdir := dlfcn
|
|||||||
headers := bits/dlfcn.h dlfcn.h
|
headers := bits/dlfcn.h dlfcn.h
|
||||||
extra-libs := libdl
|
extra-libs := libdl
|
||||||
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
|
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
|
||||||
dlmopen
|
dlmopen dlfcn
|
||||||
routines := $(patsubst %,s%,$(libdl-routines))
|
routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines)))
|
||||||
elide-routines.os := $(routines)
|
elide-routines.os := $(routines)
|
||||||
distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
|
distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
|
||||||
defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
|
defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
|
||||||
@ -34,7 +34,7 @@ include ../Makeconfig
|
|||||||
|
|
||||||
ifeq ($(versioning),yes)
|
ifeq ($(versioning),yes)
|
||||||
libdl-routines += dlopenold
|
libdl-routines += dlopenold
|
||||||
libdl-shared-only-routines := dlopenold
|
libdl-shared-only-routines := dlopenold dlfcn
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq (yes,$(build-shared))
|
ifeq (yes,$(build-shared))
|
||||||
@ -65,8 +65,6 @@ generated := $(modules-names:=.so)
|
|||||||
|
|
||||||
include ../Rules
|
include ../Rules
|
||||||
|
|
||||||
LDFLAGS-dl.so = -Wl,-dynamic-linker,$(slibdir)/$(rtld-installed-name)
|
|
||||||
|
|
||||||
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
||||||
$(test-modules): $(objpfx)%.so: $(objpfx)%.os $(common-objpfx)shlib.lds
|
$(test-modules): $(objpfx)%.so: $(objpfx)%.os $(common-objpfx)shlib.lds
|
||||||
$(build-module)
|
$(build-module)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
|
||||||
#if !defined SHARED && defined IS_IN_libdl
|
#if !defined SHARED && defined IS_IN_libdl
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ dlclose (void *handle)
|
|||||||
static void
|
static void
|
||||||
dlclose_doit (void *handle)
|
dlclose_doit (void *handle)
|
||||||
{
|
{
|
||||||
_dl_close (handle);
|
GLRO(dl_close) (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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 <errno.h>
|
||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <ldsodefs.h>
|
#include <ldsodefs.h>
|
||||||
|
|
||||||
#if !defined SHARED && defined IS_IN_libdl
|
#if !defined SHARED && defined IS_IN_libdl
|
||||||
@ -61,8 +62,10 @@ dlmopen_doit (void *a)
|
|||||||
# endif
|
# endif
|
||||||
GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
|
GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
|
||||||
|
|
||||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||||
args->caller, args->nsid);
|
args->caller,
|
||||||
|
args->nsid, __dlfcn_argc, __dlfcn_argv,
|
||||||
|
__environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
|
||||||
#if !defined SHARED && defined IS_IN_libdl
|
#if !defined SHARED && defined IS_IN_libdl
|
||||||
|
|
||||||
@ -56,8 +58,10 @@ dlopen_doit (void *a)
|
|||||||
{
|
{
|
||||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||||
|
|
||||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||||
args->caller, args->file == NULL ? LM_ID_BASE : NS);
|
args->caller,
|
||||||
|
args->file == NULL ? LM_ID_BASE : NS,
|
||||||
|
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ldsodefs.h>
|
||||||
|
|
||||||
/* This file is for compatibility with glibc 2.0. Compile it only if
|
/* This file is for compatibility with glibc 2.0. Compile it only if
|
||||||
versioning is used. */
|
versioning is used. */
|
||||||
@ -50,8 +52,10 @@ dlopen_doit (void *a)
|
|||||||
{
|
{
|
||||||
struct dlopen_args *args = (struct dlopen_args *) a;
|
struct dlopen_args *args = (struct dlopen_args *) a;
|
||||||
|
|
||||||
args->new = _dl_open (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
|
||||||
args->caller, args->file == NULL ? LM_ID_BASE : NS);
|
args->caller,
|
||||||
|
args->file == NULL ? LM_ID_BASE : NS,
|
||||||
|
__dlfcn_argc, __dlfcn_argv, __environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *__dlopen_nocheck (const char *file, int mode);
|
extern void *__dlopen_nocheck (const char *file, int mode);
|
||||||
|
15
elf/Makefile
15
elf/Makefile
@ -21,7 +21,7 @@
|
|||||||
subdir := elf
|
subdir := elf
|
||||||
|
|
||||||
headers = elf.h bits/elfclass.h link.h
|
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-addr enbl-secure dl-profstub \
|
||||||
dl-origin dl-libc dl-sym dl-tsd
|
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 \
|
dl-routines = $(addprefix dl-,load cache lookup object reloc deps \
|
||||||
runtime error init fini debug misc \
|
runtime error init fini debug misc \
|
||||||
version profile conflict tls origin \
|
version profile conflict tls origin \
|
||||||
execstack caller)
|
execstack caller open close trampoline)
|
||||||
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
|
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
|
||||||
# But they are absent from the shared libc, because that code is in ld.so.
|
# 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
|
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-array2dep.c tst-piemod1.c \
|
||||||
tst-execstack-mod.c tst-dlmodcount.c \
|
tst-execstack-mod.c tst-dlmodcount.c \
|
||||||
check-textrel.c dl-sysdep.h test-dlopenrpathmod.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-runtime.c = -fexceptions -fasynchronous-unwind-tables
|
||||||
CFLAGS-dl-lookup.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 \
|
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 \
|
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
|
||||||
$(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
|
$(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
|
# reldep9
|
||||||
test-srcs = tst-pathopt
|
test-srcs = tst-pathopt
|
||||||
tests-vis-yes = vismain
|
tests-vis-yes = vismain
|
||||||
@ -188,7 +190,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
|||||||
reldep9mod1 reldep9mod2 reldep9mod3 \
|
reldep9mod1 reldep9mod2 reldep9mod3 \
|
||||||
tst-alignmod $(modules-execstack-$(have-z-execstack)) \
|
tst-alignmod $(modules-execstack-$(have-z-execstack)) \
|
||||||
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
|
tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
|
||||||
tst-dlmopen1mod
|
tst-dlmopen1mod tst-auditmod1
|
||||||
ifeq (yes,$(have-initfini-array))
|
ifeq (yes,$(have-initfini-array))
|
||||||
modules-names += tst-array2dep
|
modules-names += tst-array2dep
|
||||||
endif
|
endif
|
||||||
@ -773,3 +775,6 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
|
|||||||
|
|
||||||
$(objpfx)tst-dlmopen3: $(libdl)
|
$(objpfx)tst-dlmopen3: $(libdl)
|
||||||
$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
$(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
|
%endif
|
||||||
GLIBC_PRIVATE {
|
GLIBC_PRIVATE {
|
||||||
# functions used in other libraries
|
# functions used in other libraries
|
||||||
_dl_open; _dl_close; _dl_addr;
|
_dl_addr;
|
||||||
_dl_sym; _dl_vsym;
|
_dl_sym; _dl_vsym;
|
||||||
_dl_open_hook;
|
_dl_open_hook;
|
||||||
__libc_dlopen_mode; __libc_dlsym; __libc_dlclose;
|
__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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <bits/libc-lock.h>
|
#include <bits/libc-lock.h>
|
||||||
#include <ldsodefs.h>
|
#include <ldsodefs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -99,7 +100,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
internal_function
|
|
||||||
_dl_close (void *_map)
|
_dl_close (void *_map)
|
||||||
{
|
{
|
||||||
struct reldep_list
|
struct reldep_list
|
||||||
@ -112,6 +112,7 @@ _dl_close (void *_map)
|
|||||||
} *reldeps = NULL;
|
} *reldeps = NULL;
|
||||||
struct link_map **list;
|
struct link_map **list;
|
||||||
struct link_map *map = _map;
|
struct link_map *map = _map;
|
||||||
|
Lmid_t ns = map->l_ns;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int *new_opencount;
|
unsigned int *new_opencount;
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
@ -139,8 +140,8 @@ _dl_close (void *_map)
|
|||||||
{
|
{
|
||||||
/* There are still references to this object. Do nothing more. */
|
/* There are still references to this object. Do nothing more. */
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||||
GLRO(dl_debug_printf) ("\nclosing file=%s; opencount == %u\n",
|
_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
|
||||||
map->l_name, map->l_opencount);
|
map->l_name, map->l_opencount);
|
||||||
|
|
||||||
/* Decrement the object's reference counter, not the dependencies'. */
|
/* Decrement the object's reference counter, not the dependencies'. */
|
||||||
--map->l_opencount;
|
--map->l_opencount;
|
||||||
@ -268,13 +269,17 @@ _dl_close (void *_map)
|
|||||||
for (i = 0; list[i] != NULL; ++i)
|
for (i = 0; list[i] != NULL; ++i)
|
||||||
{
|
{
|
||||||
struct link_map *imap = list[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
|
if (new_opencount[i] == 0 && imap->l_type == lt_loaded
|
||||||
&& (imap->l_flags_1 & DF_1_NODELETE) == 0)
|
&& (imap->l_flags_1 & DF_1_NODELETE) == 0)
|
||||||
{
|
{
|
||||||
/* When debugging print a message first. */
|
/* When debugging print a message first. */
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||||
GLRO(dl_debug_printf) ("\ncalling fini: %s [%lu]\n\n",
|
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||||
imap->l_name, imap->l_ns);
|
imap->l_name, ns);
|
||||||
|
|
||||||
/* Call its termination function. Do not do it for
|
/* Call its termination function. Do not do it for
|
||||||
half-cooked objects. */
|
half-cooked objects. */
|
||||||
@ -299,6 +304,22 @@ _dl_close (void *_map)
|
|||||||
+ imap->l_info[DT_FINI]->d_un.d_ptr))) ();
|
+ 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
|
/* This object must not be used anymore. We must remove the
|
||||||
reference from the scope. */
|
reference from the scope. */
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
@ -365,9 +386,30 @@ _dl_close (void *_map)
|
|||||||
assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
|
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. */
|
/* Notify the debugger we are about to remove some loaded objects. */
|
||||||
_r_debug.r_state = RT_DELETE;
|
struct r_debug *r = _dl_debug_initialize (0);
|
||||||
GLRO(dl_debug_state) ();
|
r->r_state = RT_DELETE;
|
||||||
|
_dl_debug_state ();
|
||||||
|
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
size_t tls_free_start;
|
size_t tls_free_start;
|
||||||
@ -389,21 +431,19 @@ _dl_close (void *_map)
|
|||||||
if (__builtin_expect (imap->l_global, 0))
|
if (__builtin_expect (imap->l_global, 0))
|
||||||
{
|
{
|
||||||
/* This object is in the global scope list. Remove it. */
|
/* This object is in the global scope list. Remove it. */
|
||||||
unsigned int cnt
|
unsigned int cnt = GL(dl_ns)[ns]._ns_main_searchlist->r_nlist;
|
||||||
= GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
--cnt;
|
--cnt;
|
||||||
while (GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt]
|
while (GL(dl_ns)[ns]._ns_main_searchlist->r_list[cnt] != imap);
|
||||||
!= imap);
|
|
||||||
|
|
||||||
/* The object was already correctly registered. */
|
/* The object was already correctly registered. */
|
||||||
while (++cnt
|
while (++cnt
|
||||||
< GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_nlist)
|
< GL(dl_ns)[ns]._ns_main_searchlist->r_nlist)
|
||||||
GL(dl_ns)[imap->l_ns]._ns_main_searchlist->r_list[cnt - 1]
|
GL(dl_ns)[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_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
|
#ifdef USE_TLS
|
||||||
@ -412,9 +452,10 @@ _dl_close (void *_map)
|
|||||||
{
|
{
|
||||||
any_tls = true;
|
any_tls = true;
|
||||||
|
|
||||||
if (! remove_slotinfo (imap->l_tls_modid,
|
if (GL(dl_tls_dtv_slotinfo_list) != NULL
|
||||||
GL(dl_tls_dtv_slotinfo_list), 0,
|
&& ! remove_slotinfo (imap->l_tls_modid,
|
||||||
imap->l_init_called))
|
GL(dl_tls_dtv_slotinfo_list), 0,
|
||||||
|
imap->l_init_called))
|
||||||
/* All dynamically loaded modules with TLS are unloaded. */
|
/* All dynamically loaded modules with TLS are unloaded. */
|
||||||
GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
|
GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
|
||||||
|
|
||||||
@ -499,12 +540,12 @@ _dl_close (void *_map)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef SHARED
|
#ifdef SHARED
|
||||||
assert (imap->l_ns != LM_ID_BASE);
|
assert (ns != LM_ID_BASE);
|
||||||
#endif
|
#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)
|
if (imap->l_next != NULL)
|
||||||
imap->l_next->l_prev = imap->l_prev;
|
imap->l_next->l_prev = imap->l_prev;
|
||||||
|
|
||||||
@ -579,16 +620,36 @@ _dl_close (void *_map)
|
|||||||
if (any_tls)
|
if (any_tls)
|
||||||
{
|
{
|
||||||
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
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))
|
if (tls_free_end == GL(dl_tls_static_used))
|
||||||
GL(dl_tls_static_used) = tls_free_start;
|
GL(dl_tls_static_used) = tls_free_start;
|
||||||
}
|
}
|
||||||
#endif
|
#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. */
|
/* Notify the debugger those objects are finalized and gone. */
|
||||||
_r_debug.r_state = RT_CONSISTENT;
|
r->r_state = RT_CONSISTENT;
|
||||||
GLRO(dl_debug_state) ();
|
_dl_debug_state ();
|
||||||
|
|
||||||
/* Now we can perhaps also remove the modules for which we had
|
/* Now we can perhaps also remove the modules for which we had
|
||||||
dependencies because of symbol lookup. */
|
dependencies because of symbol lookup. */
|
||||||
@ -612,7 +673,6 @@ _dl_close (void *_map)
|
|||||||
/* Release the lock. */
|
/* Release the lock. */
|
||||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
}
|
}
|
||||||
libc_hidden_def (_dl_close)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
|
@ -34,7 +34,7 @@ struct r_debug *
|
|||||||
internal_function
|
internal_function
|
||||||
_dl_debug_initialize (ElfW(Addr) ldbase)
|
_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. */
|
/* Tell the debugger where to find the map of loaded objects. */
|
||||||
_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
|
_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
|
||||||
|
@ -53,7 +53,12 @@ _dl_fini (void)
|
|||||||
/* Protect against concurrent loads and unloads. */
|
/* Protect against concurrent loads and unloads. */
|
||||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||||
|
|
||||||
|
unsigned int nmaps = 0;
|
||||||
unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded;
|
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
|
/* XXX Could it be (in static binaries) that there is no object
|
||||||
loaded? */
|
loaded? */
|
||||||
@ -76,6 +81,7 @@ _dl_fini (void)
|
|||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct link_map *l;
|
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)
|
for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
|
||||||
/* Do not handle ld.so in secondary namespaces. */
|
/* Do not handle ld.so in secondary namespaces. */
|
||||||
if (l == l->l_real)
|
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);
|
||||||
assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
|
||||||
unsigned int nmaps = i;
|
nmaps = i;
|
||||||
|
|
||||||
if (nmaps != 0)
|
if (nmaps != 0)
|
||||||
{
|
{
|
||||||
@ -163,6 +169,7 @@ _dl_fini (void)
|
|||||||
high and will be decremented in this loop. So we release the
|
high and will be decremented in this loop. So we release the
|
||||||
lock so that some code which might be called from a destructor
|
lock so that some code which might be called from a destructor
|
||||||
can directly or indirectly access the lock. */
|
can directly or indirectly access the lock. */
|
||||||
|
out:
|
||||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
|
|
||||||
/* 'maps' now contains the objects in the right order. Now call the
|
/* '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. */
|
/* Make sure nothing happens if we are called twice. */
|
||||||
l->l_init_called = 0;
|
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? */
|
/* Is there a destructor function? */
|
||||||
if (l->l_info[DT_FINI_ARRAY] == NULL
|
if (l->l_info[DT_FINI_ARRAY] != NULL
|
||||||
&& l->l_info[DT_FINI] == 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)
|
|
||||||
{
|
{
|
||||||
ElfW(Addr) *array =
|
/* When debugging print a message first. */
|
||||||
(ElfW(Addr) *) (l->l_addr
|
if (__builtin_expect (GLRO(dl_debug_mask)
|
||||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
& DL_DEBUG_IMPCALLS, 0))
|
||||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
_dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
|
||||||
/ sizeof (ElfW(Addr)));
|
l->l_name[0] ? l->l_name : rtld_progname,
|
||||||
while (i-- > 0)
|
cnt);
|
||||||
((fini_t) array[i]) ();
|
|
||||||
|
/* 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. */
|
#ifdef SHARED
|
||||||
if (l->l_info[DT_FINI] != NULL)
|
/* Auditing checkpoint: another object closed. */
|
||||||
((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
|
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. */
|
/* 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 = main_map->l_info[DT_PREINIT_ARRAY];
|
||||||
ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
|
ElfW(Dyn) *preinit_array_size = main_map->l_info[DT_PREINIT_ARRAYSZ];
|
||||||
struct r_debug *r;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (__builtin_expect (GL(dl_initfirst) != NULL, 0))
|
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);
|
((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
|
/* Stupid users forced the ELF specification to be changed. It now
|
||||||
says that the dynamic loader is responsible for determining the
|
says that the dynamic loader is responsible for determining the
|
||||||
order in which the constructors have to run. The constructors
|
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)
|
while (i-- > 0)
|
||||||
call_init (main_map->l_initfini[i], argc, argv, env);
|
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
|
#ifndef HAVE_INLINED_SYSCALLS
|
||||||
/* Finished starting up. */
|
/* Finished starting up. */
|
||||||
INTUSE(_dl_starting_up) = 0;
|
INTUSE(_dl_starting_up) = 0;
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ldsodefs.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
|
/* The purpose of this file is to provide wrappers around the dynamic
|
||||||
linker error mechanism (similar to dlopen() et al in libdl) which
|
linker error mechanism (similar to dlopen() et al in libdl) which
|
||||||
are usable from within libc. Generally we want to throw away the
|
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;
|
struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
|
||||||
/* Open and relocate the shared object. */
|
/* 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
|
static void
|
||||||
@ -93,7 +99,7 @@ do_dlsym (void *ptr)
|
|||||||
static void
|
static void
|
||||||
do_dlclose (void *ptr)
|
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
|
/* This code is to support __libc_dlopen from __libc_dlopen'ed shared
|
||||||
@ -109,7 +115,7 @@ struct dl_open_hook
|
|||||||
#ifdef SHARED
|
#ifdef SHARED
|
||||||
extern struct dl_open_hook *_dl_open_hook;
|
extern struct dl_open_hook *_dl_open_hook;
|
||||||
libc_hidden_proto (_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);
|
libc_hidden_data_def (_dl_open_hook);
|
||||||
#else
|
#else
|
||||||
static void
|
static void
|
||||||
@ -119,7 +125,7 @@ do_dlsym_private (void *ptr)
|
|||||||
struct r_found_version vers;
|
struct r_found_version vers;
|
||||||
vers.name = "GLIBC_PRIVATE";
|
vers.name = "GLIBC_PRIVATE";
|
||||||
vers.hidden = 1;
|
vers.hidden = 1;
|
||||||
/* vers.hash = _dl_elf_hash (version); */
|
/* vers.hash = _dl_elf_hash (vers.name); */
|
||||||
vers.hash = 0x0963cf85;
|
vers.hash = 0x0963cf85;
|
||||||
vers.filename = NULL;
|
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. */
|
/* Initialize to keep the compiler happy. */
|
||||||
const char *errstring = NULL;
|
const char *errstring = NULL;
|
||||||
int errval = 0;
|
int errval = 0;
|
||||||
|
struct r_debug *r = _dl_debug_initialize (0);
|
||||||
|
bool make_consistent = false;
|
||||||
|
|
||||||
/* Get file information. */
|
/* Get file information. */
|
||||||
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st) < 0, 0))
|
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:
|
call_lose_errno:
|
||||||
errval = errno;
|
errval = errno;
|
||||||
call_lose:
|
call_lose:
|
||||||
|
if (make_consistent)
|
||||||
|
{
|
||||||
|
r->r_state = RT_CONSISTENT;
|
||||||
|
_dl_debug_state ();
|
||||||
|
}
|
||||||
|
|
||||||
lose (errval, fd, name, realname, l, errstring);
|
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
|
#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. */
|
/* Enter the new object in the list of loaded objects. */
|
||||||
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
|
||||||
if (__builtin_expect (l == NULL, 0))
|
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
|
# 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
|
/* We are loading the executable itself when the dynamic linker
|
||||||
was executed directly. The setup will happen later. */
|
was executed directly. The setup will happen later. */
|
||||||
break;
|
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])
|
add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
|
||||||
+ l->l_info[DT_SONAME]->d_un.d_val));
|
+ 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;
|
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
|
this could mean there is something wrong in the installation and the
|
||||||
user might want to know about this. */
|
user might want to know about this. */
|
||||||
static int
|
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. */
|
/* This is the expected ELF header. */
|
||||||
#define ELF32_CLASS ELFCLASS32
|
#define ELF32_CLASS ELFCLASS32
|
||||||
@ -1500,13 +1562,34 @@ open_verify (const char *name, struct filebuf *fbp)
|
|||||||
ElfW(Word) type;
|
ElfW(Word) type;
|
||||||
char vendor[4];
|
char vendor[4];
|
||||||
} expected_note = { 4, 16, 1, "GNU" };
|
} expected_note = { 4, 16, 1, "GNU" };
|
||||||
int fd;
|
|
||||||
/* Initialize it to make the compiler happy. */
|
/* Initialize it to make the compiler happy. */
|
||||||
const char *errstring = NULL;
|
const char *errstring = NULL;
|
||||||
int errval = 0;
|
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. */
|
/* Open the file. We always open files read-only. */
|
||||||
fd = __open (name, O_RDONLY);
|
int fd = __open (name, O_RDONLY);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
{
|
{
|
||||||
ElfW(Ehdr) *ehdr;
|
ElfW(Ehdr) *ehdr;
|
||||||
@ -1664,7 +1747,7 @@ open_verify (const char *name, struct filebuf *fbp)
|
|||||||
static int
|
static int
|
||||||
open_path (const char *name, size_t namelen, int preloaded,
|
open_path (const char *name, size_t namelen, int preloaded,
|
||||||
struct r_search_path_struct *sps, char **realname,
|
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;
|
struct r_search_path_elem **dirs = sps->dirs;
|
||||||
char *buf;
|
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))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
||||||
_dl_debug_printf (" trying file=%s\n", buf);
|
_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 (this_dir->status[cnt] == unknown)
|
||||||
{
|
{
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
this_dir->status[cnt] = existing;
|
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
|
/* We failed to open machine dependent library. Let's
|
||||||
test whether there is any directory at all. */
|
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. */
|
/* 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)
|
if (fd != -1 && __builtin_expect (preloaded, 0)
|
||||||
&& INTUSE(__libc_enable_secure))
|
&& 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[0]
|
||||||
? loader->l_name : rtld_progname, loader->l_ns);
|
? 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)
|
if (strchr (name, '/') == NULL)
|
||||||
{
|
{
|
||||||
/* Search for NAME in several places. */
|
/* 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)
|
for (l = loader; fd == -1 && l; l = l->l_loader)
|
||||||
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||||
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
|
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
|
/* If dynamically linked, try the DT_RPATH of the executable
|
||||||
itself. NB: we do this for lookups in any namespace. */
|
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
|
if (l && l->l_type != lt_loaded && l != loader
|
||||||
&& cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
&& cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
|
||||||
fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
|
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. */
|
/* Try the LD_LIBRARY_PATH environment variable. */
|
||||||
if (fd == -1 && env_path_list.dirs != (void *) -1)
|
if (fd == -1 && env_path_list.dirs != (void *) -1)
|
||||||
fd = open_path (name, namelen, preloaded, &env_path_list,
|
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. */
|
/* Look at the RUNPATH information for this binary. */
|
||||||
if (fd == -1 && loader != NULL
|
if (fd == -1 && loader != NULL
|
||||||
&& cache_rpath (loader, &loader->l_runpath_dirs,
|
&& cache_rpath (loader, &loader->l_runpath_dirs,
|
||||||
DT_RUNPATH, "RUNPATH"))
|
DT_RUNPATH, "RUNPATH"))
|
||||||
fd = open_path (name, namelen, preloaded,
|
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
|
if (fd == -1
|
||||||
&& (__builtin_expect (! preloaded, 1)
|
&& (__builtin_expect (! preloaded, 1)
|
||||||
@ -1939,7 +2055,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
|
|||||||
|
|
||||||
if (cached != NULL)
|
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))
|
if (__builtin_expect (fd != -1, 1))
|
||||||
{
|
{
|
||||||
realname = local_strdup (cached);
|
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))
|
|| __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
|
||||||
&& rtld_search_dirs.dirs != (void *) -1)
|
&& rtld_search_dirs.dirs != (void *) -1)
|
||||||
fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
|
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. */
|
/* Add another newline when we are tracing the library loading. */
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
|
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;
|
fd = -1;
|
||||||
else
|
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)
|
if (__builtin_expect (fd, 0) == -1)
|
||||||
free (realname);
|
free (realname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SHARED
|
||||||
|
no_file:
|
||||||
|
#endif
|
||||||
/* In case the LOADER information has only been provided to get to
|
/* In case the LOADER information has only been provided to get to
|
||||||
the appropriate RUNPATH/RPATH information we do not need it
|
the appropriate RUNPATH/RPATH information we do not need it
|
||||||
anymore. */
|
anymore. */
|
||||||
|
@ -39,14 +39,24 @@ _dl_new_object (char *realname, const char *libname, int type,
|
|||||||
size_t libname_len = strlen (libname) + 1;
|
size_t libname_len = strlen (libname) + 1;
|
||||||
struct link_map *new;
|
struct link_map *new;
|
||||||
struct libname_list *newname;
|
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)
|
new = (struct link_map *) calloc (sizeof (*new) + audit_space
|
||||||
+ libname_len, 1);
|
+ sizeof (*newname) + libname_len, 1);
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
new->l_real = new;
|
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->name = (char *) memcpy (newname + 1, libname, libname_len);
|
||||||
/* newname->next = NULL; We use calloc therefore not necessary. */
|
/* newname->next = NULL; We use calloc therefore not necessary. */
|
||||||
newname->dont_free = 1;
|
newname->dont_free = 1;
|
||||||
@ -59,6 +69,14 @@ _dl_new_object (char *realname, const char *libname, int type,
|
|||||||
#endif
|
#endif
|
||||||
new->l_ns = nsid;
|
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. */
|
/* new->l_global = 0; We use calloc therefore not necessary. */
|
||||||
|
|
||||||
/* Use the 'l_scope_mem' array by default for the the 'l_scope'
|
/* 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_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. */
|
/* Undefine the following for debugging. */
|
||||||
/* #define SCOPE_DEBUG 1 */
|
/* #define SCOPE_DEBUG 1 */
|
||||||
#ifdef SCOPE_DEBUG
|
#ifdef SCOPE_DEBUG
|
||||||
@ -74,6 +69,10 @@ struct dl_open_args
|
|||||||
struct link_map *map;
|
struct link_map *map;
|
||||||
/* Namespace ID. */
|
/* Namespace ID. */
|
||||||
Lmid_t nsid;
|
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;
|
GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
|
||||||
nomem:
|
nomem:
|
||||||
GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL,
|
_dl_signal_error (ENOMEM, new->l_libname->name, NULL,
|
||||||
N_("cannot extend global scope"));
|
N_("cannot extend global scope"));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,13 +170,16 @@ dl_open_worker (void *a)
|
|||||||
int lazy;
|
int lazy;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
bool any_tls;
|
bool any_tls = false;
|
||||||
#endif
|
#endif
|
||||||
struct link_map *call_map = NULL;
|
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. */
|
/* Check whether _dl_open() has been called from a valid DSO. */
|
||||||
if (__check_caller (args->caller_dl_open, allow_libc|allow_libdl) != 0)
|
if (__check_caller (args->caller_dl_open,
|
||||||
GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller"));
|
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
|
/* 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
|
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;
|
char *new_file;
|
||||||
|
|
||||||
/* DSTs must not appear in SUID/SGID programs. */
|
/* DSTs must not appear in SUID/SGID programs. */
|
||||||
if (__libc_enable_secure)
|
if (INTUSE(__libc_enable_secure))
|
||||||
/* This is an error. */
|
/* This is an error. */
|
||||||
GLRO(dl_signal_error) (0, "dlopen", NULL,
|
_dl_signal_error (0, "dlopen", NULL,
|
||||||
N_("DST not allowed in SUID/SGID programs"));
|
N_("DST not allowed in SUID/SGID programs"));
|
||||||
|
|
||||||
|
|
||||||
/* Determine how much space we need. We have to allocate the
|
/* 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 the substitution failed don't try to load. */
|
||||||
if (*new_file == '\0')
|
if (*new_file == '\0')
|
||||||
GLRO(dl_signal_error) (0, "dlopen", NULL,
|
_dl_signal_error (0, "dlopen", NULL,
|
||||||
N_("empty dynamic string token substitution"));
|
N_("empty dynamic string token substitution"));
|
||||||
|
|
||||||
/* Now we have a new file name. */
|
/* Now we have a new file name. */
|
||||||
file = new_file;
|
file = new_file;
|
||||||
@ -256,8 +258,8 @@ dl_open_worker (void *a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load the named object. */
|
/* Load the named object. */
|
||||||
args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
|
args->map = new = _dl_map_object (call_map, file, 0, lt_loaded, 0,
|
||||||
mode | __RTLD_CALLMAP, args->nsid);
|
mode | __RTLD_CALLMAP, args->nsid);
|
||||||
|
|
||||||
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
|
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
|
||||||
set and the object is not already loaded. */
|
set and the object is not already loaded. */
|
||||||
@ -279,8 +281,8 @@ dl_open_worker (void *a)
|
|||||||
{
|
{
|
||||||
/* Let the user know about the opencount. */
|
/* Let the user know about the opencount. */
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
_dl_debug_printf ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||||
new->l_name, new->l_ns, new->l_opencount);
|
new->l_name, new->l_ns, new->l_opencount);
|
||||||
|
|
||||||
/* If the user requested the object to be in the global namespace
|
/* If the user requested the object to be in the global namespace
|
||||||
but it is not so far, add it now. */
|
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. */
|
/* Increment just the reference counter of the object. */
|
||||||
++new->l_opencount;
|
++new->l_opencount;
|
||||||
|
|
||||||
|
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load that object's dependencies. */
|
/* Load that object's dependencies. */
|
||||||
GLRO(dl_map_object_deps) (new, NULL, 0, 0,
|
_dl_map_object_deps (new, NULL, 0, 0,
|
||||||
mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
|
mode & (__RTLD_DLOPEN | RTLD_DEEPBIND));
|
||||||
|
|
||||||
/* So far, so good. Now check the versions. */
|
/* So far, so good. Now check the versions. */
|
||||||
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
for (i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||||
if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
|
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,
|
(void) _dl_check_map_versions (new->l_searchlist.r_list[i]->l_real,
|
||||||
0, 0);
|
0, 0);
|
||||||
|
|
||||||
#ifdef SCOPE_DEBUG
|
#ifdef SCOPE_DEBUG
|
||||||
show_scope (new);
|
show_scope (new);
|
||||||
#endif
|
#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. */
|
/* Only do lazy relocation if `LD_BIND_NOW' is not set. */
|
||||||
lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && GLRO(dl_lazy);
|
lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && GLRO(dl_lazy);
|
||||||
|
|
||||||
@ -336,12 +365,12 @@ dl_open_worker (void *a)
|
|||||||
start the profiling. */
|
start the profiling. */
|
||||||
struct link_map *old_profile_map = GL(dl_profile_map);
|
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)
|
if (old_profile_map == NULL && GL(dl_profile_map) != NULL)
|
||||||
{
|
{
|
||||||
/* We must prepare the profiling. */
|
/* We must prepare the profiling. */
|
||||||
GLRO(dl_start_profile) ();
|
_dl_start_profile ();
|
||||||
|
|
||||||
/* Prevent unloading the object. */
|
/* Prevent unloading the object. */
|
||||||
GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
|
GL(dl_profile_map)->l_flags_1 |= DF_1_NODELETE;
|
||||||
@ -349,7 +378,7 @@ dl_open_worker (void *a)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
GLRO(dl_relocate_object) (l, l->l_scope, lazy, 0);
|
_dl_relocate_object (l, l->l_scope, lazy, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l == new)
|
if (l == new)
|
||||||
@ -357,22 +386,6 @@ dl_open_worker (void *a)
|
|||||||
l = l->l_prev;
|
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
|
/* Increment the open count for all dependencies. If the file is
|
||||||
not loaded as a dependency here add the search list of the newly
|
not loaded as a dependency here add the search list of the newly
|
||||||
loaded object to the scope. */
|
loaded object to the scope. */
|
||||||
@ -412,8 +425,8 @@ dl_open_worker (void *a)
|
|||||||
newp = (struct r_scope_elem **)
|
newp = (struct r_scope_elem **)
|
||||||
malloc (new_size * sizeof (struct r_scope_elem *));
|
malloc (new_size * sizeof (struct r_scope_elem *));
|
||||||
if (newp == NULL)
|
if (newp == NULL)
|
||||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
_dl_signal_error (ENOMEM, "dlopen", NULL,
|
||||||
N_("cannot create scope list"));
|
N_("cannot create scope list"));
|
||||||
imap->l_scope = memcpy (newp, imap->l_scope,
|
imap->l_scope = memcpy (newp, imap->l_scope,
|
||||||
cnt * sizeof (imap->l_scope[0]));
|
cnt * sizeof (imap->l_scope[0]));
|
||||||
}
|
}
|
||||||
@ -423,8 +436,8 @@ dl_open_worker (void *a)
|
|||||||
realloc (imap->l_scope,
|
realloc (imap->l_scope,
|
||||||
new_size * sizeof (struct r_scope_elem *));
|
new_size * sizeof (struct r_scope_elem *));
|
||||||
if (newp == NULL)
|
if (newp == NULL)
|
||||||
GLRO(dl_signal_error) (ENOMEM, "dlopen", NULL,
|
_dl_signal_error (ENOMEM, "dlopen", NULL,
|
||||||
N_("cannot create scope list"));
|
N_("cannot create scope list"));
|
||||||
imap->l_scope = newp;
|
imap->l_scope = newp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,76 +454,35 @@ dl_open_worker (void *a)
|
|||||||
> 0, 0))
|
> 0, 0))
|
||||||
{
|
{
|
||||||
/* Now that we know the object is loaded successfully add
|
/* 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. */
|
might have to increase its size. */
|
||||||
struct dtv_slotinfo_list *listp;
|
_dl_add_to_slotinfo (new->l_searchlist.r_list[i]);
|
||||||
struct dtv_slotinfo_list *prevp;
|
|
||||||
size_t idx = new->l_searchlist.r_list[i]->l_tls_modid;
|
|
||||||
|
|
||||||
assert (new->l_searchlist.r_list[i]->l_type == lt_loaded);
|
if (new->l_searchlist.r_list[i]->l_need_tls_init)
|
||||||
|
|
||||||
/* 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? */
|
new->l_searchlist.r_list[i]->l_need_tls_init = 0;
|
||||||
if (idx < listp->len)
|
# ifdef SHARED
|
||||||
break;
|
/* Update the slot information data for at least the
|
||||||
idx -= listp->len;
|
generation of the DSO we are allocating data for. */
|
||||||
prevp = listp;
|
_dl_update_slotinfo (new->l_searchlist.r_list[i]->l_tls_modid);
|
||||||
listp = listp->next;
|
# 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. */
|
/* We have to bump the generation counter. */
|
||||||
any_tls = true;
|
any_tls = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bump the generation number if necessary. */
|
/* Bump the generation number if necessary. */
|
||||||
if (any_tls)
|
if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
||||||
if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
|
_dl_fatal_printf (N_("\
|
||||||
__libc_fatal (_("TLS generation counter wrapped! Please report this."));
|
TLS generation counter wrapped! Please report this."));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Run the initializer functions of new objects. */
|
/* 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. */
|
/* Now we can make the new map available in the global scope. */
|
||||||
if (mode & RTLD_GLOBAL)
|
if (mode & RTLD_GLOBAL)
|
||||||
@ -532,14 +504,14 @@ cannot create TLS data structures"));
|
|||||||
|
|
||||||
/* Let the user know about the opencount. */
|
/* Let the user know about the opencount. */
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
|
||||||
GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
|
_dl_debug_printf ("opening file=%s [%lu]; opencount=%u\n\n",
|
||||||
new->l_name, new->l_ns, new->l_opencount);
|
new->l_name, new->l_ns, new->l_opencount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
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;
|
struct dl_open_args args;
|
||||||
const char *objname;
|
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)
|
if ((mode & RTLD_BINDING_MASK) == 0)
|
||||||
/* One of the flags must be set. */
|
/* One of the flags must be set. */
|
||||||
GLRO(dl_signal_error) (EINVAL, file, NULL,
|
_dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));
|
||||||
N_("invalid mode for dlopen()"));
|
|
||||||
|
|
||||||
/* Make sure we are alone. */
|
/* Make sure we are alone. */
|
||||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||||
|
|
||||||
|
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
if (nsid == LM_ID_NEWLM)
|
if (nsid == LM_ID_NEWLM)
|
||||||
{
|
{
|
||||||
/* Find a new namespace. */
|
/* 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. */
|
/* No more namespace available. */
|
||||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
__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()"));
|
no more namespaces available for dlmopen()"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
/* 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
|
else if (nsid != LM_ID_BASE && nsid != __LM_ID_CALLER
|
||||||
&& GL(dl_ns)[nsid]._ns_nloaded == 0)
|
&& (GL(dl_ns)[nsid]._ns_nloaded == 0
|
||||||
GLRO(dl_signal_error) (EINVAL, file, NULL,
|
|| GL(dl_ns)[nsid]._ns_loaded->l_auditing))
|
||||||
N_("invalid target namespace in dlmopen()"));
|
_dl_signal_error (EINVAL, file, NULL,
|
||||||
|
N_("invalid target namespace in dlmopen()"));
|
||||||
|
|
||||||
args.file = file;
|
args.file = file;
|
||||||
args.mode = mode;
|
args.mode = mode;
|
||||||
@ -583,11 +558,14 @@ no more namespaces available for dlmopen()"));
|
|||||||
args.caller_dl_open = RETURN_ADDRESS (0);
|
args.caller_dl_open = RETURN_ADDRESS (0);
|
||||||
args.map = NULL;
|
args.map = NULL;
|
||||||
args.nsid = nsid;
|
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
|
#ifndef MAP_COPY
|
||||||
/* We must munmap() the cache file. */
|
/* We must munmap() the cache file. */
|
||||||
GLRO(dl_unload_cache) ();
|
_dl_unload_cache ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Release the lock. */
|
/* Release the lock. */
|
||||||
@ -603,21 +581,22 @@ no more namespaces available for dlmopen()"));
|
|||||||
state if relocation failed, for example. */
|
state if relocation failed, for example. */
|
||||||
if (args.map)
|
if (args.map)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
/* Increment open counters for all objects since this
|
/* Increment open counters for all objects since this
|
||||||
sometimes has not happened yet. */
|
sometimes has not happened yet. */
|
||||||
if (args.map->l_searchlist.r_list[0]->l_opencount == 0)
|
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;
|
++args.map->l_searchlist.r_list[i]->l_opencount;
|
||||||
|
|
||||||
#ifdef USE_TLS
|
#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
|
Since it will be removed in the following _dl_close call
|
||||||
we have to mark the dtv array as having gaps to fill
|
we have to mark the dtv array as having gaps to fill the
|
||||||
the holes. This is a pessimistic assumption which won't
|
holes. This is a pessimistic assumption which won't hurt
|
||||||
hurt if not true. */
|
if not true. There is no need to do this when we are
|
||||||
GL(dl_tls_dtv_gaps) = true;
|
loading the auditing DSOs since TLS has not yet been set
|
||||||
|
up. */
|
||||||
|
if ((mode & __RTLD_AUDIT) == 0)
|
||||||
|
GL(dl_tls_dtv_gaps) = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_dl_close (args.map);
|
_dl_close (args.map);
|
||||||
@ -639,20 +618,23 @@ no more namespaces available for dlmopen()"));
|
|||||||
memcpy (local_errstring, errstring, len_errstring);
|
memcpy (local_errstring, errstring, len_errstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errstring != _dl_out_of_memory)
|
if (errstring != INTUSE(_dl_out_of_memory))
|
||||||
free ((char *) errstring);
|
free ((char *) errstring);
|
||||||
|
|
||||||
|
assert (_dl_debug_initialize (0)->r_state == RT_CONSISTENT);
|
||||||
|
|
||||||
/* Reraise the error. */
|
/* 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
|
#ifndef SHARED
|
||||||
DL_STATIC_INIT (args.map);
|
DL_STATIC_INIT (args.map);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return args.map;
|
return args.map;
|
||||||
}
|
}
|
||||||
libc_hidden_def (_dl_open)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SCOPE_DEBUG
|
#ifdef SCOPE_DEBUG
|
||||||
|
@ -48,8 +48,6 @@ void
|
|||||||
internal_function __attribute_noinline__
|
internal_function __attribute_noinline__
|
||||||
_dl_allocate_static_tls (struct link_map *map)
|
_dl_allocate_static_tls (struct link_map *map)
|
||||||
{
|
{
|
||||||
size_t offset;
|
|
||||||
|
|
||||||
/* If the alignment requirements are too high fail. */
|
/* If the alignment requirements are too high fail. */
|
||||||
if (map->l_tls_align > GL(dl_tls_static_align))
|
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;
|
n = (freebytes - blsize) / map->l_tls_align;
|
||||||
|
|
||||||
offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
|
size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
|
||||||
- map->l_tls_firstbyte_offset);
|
- map->l_tls_firstbyte_offset);
|
||||||
|
|
||||||
map->l_tls_offset = GL(dl_tls_static_used) = offset;
|
map->l_tls_offset = GL(dl_tls_static_used) = offset;
|
||||||
# elif TLS_DTV_AT_TP
|
# elif TLS_DTV_AT_TP
|
||||||
size_t used;
|
size_t used;
|
||||||
size_t check;
|
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;
|
used = offset + map->l_tls_blocksize;
|
||||||
check = used;
|
check = used;
|
||||||
/* dl_tls_static_used includes the TCB at the beginning. */
|
/* 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"
|
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
if (map->l_relocated)
|
/* If the object is not yet relocated we cannot initialize the
|
||||||
GL(dl_init_static_tls) (map);
|
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
|
else
|
||||||
map->l_need_tls_init = 1;
|
map->l_need_tls_init = 1;
|
||||||
}
|
}
|
||||||
@ -114,7 +124,8 @@ _dl_nothread_init_static_tls (struct link_map *map)
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
/* 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. */
|
/* Initialize the memory. */
|
||||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
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. */
|
/* Initialize it to make the compiler happy. */
|
||||||
const char *errstring = NULL;
|
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)
|
if (l->l_relocated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If DT_BIND_NOW is set relocate all references in this object. We
|
/* If DT_BIND_NOW is set relocate all references in this object. We
|
||||||
do not do this if we are profiling, of course. */
|
do not do this if we are profiling, of course. */
|
||||||
|
// XXX Correct for auditing?
|
||||||
if (!consider_profiling
|
if (!consider_profiling
|
||||||
&& __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
|
&& __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
|
||||||
lazy = 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.ret = (*ref); \
|
||||||
l->l_lookup_cache.value = _lr; })) \
|
l->l_lookup_cache.value = _lr; })) \
|
||||||
: l)
|
: 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
|
/* 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
|
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. */
|
will be NULL. */
|
||||||
if (l->l_info[DT_PLTRELSZ] == 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:
|
fatal:
|
||||||
_dl_fatal_printf (errstring,
|
_dl_fatal_printf (errstring,
|
||||||
rtld_progname ?: "<program name unknown>",
|
rtld_progname ?: "<program name unknown>",
|
||||||
l->l_name);
|
l->l_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
l->l_reloc_result =
|
l->l_reloc_result = calloc (sizeof (l->l_reloc_result[0]),
|
||||||
(ElfW(Addr) *) calloc (sizeof (ElfW(Addr)),
|
l->l_info[DT_PLTRELSZ]->d_un.d_val);
|
||||||
l->l_info[DT_PLTRELSZ]->d_un.d_val);
|
|
||||||
if (l->l_reloc_result == NULL)
|
if (l->l_reloc_result == NULL)
|
||||||
{
|
{
|
||||||
errstring = N_("\
|
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;
|
goto fatal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
270
elf/dl-runtime.c
270
elf/dl-runtime.c
@ -1,5 +1,5 @@
|
|||||||
/* On-demand PLT fixup for shared objects.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -51,15 +51,15 @@
|
|||||||
function. */
|
function. */
|
||||||
|
|
||||||
#ifndef ELF_MACHINE_NO_PLT
|
#ifndef ELF_MACHINE_NO_PLT
|
||||||
static ElfW(Addr)
|
ElfW(Addr)
|
||||||
__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
|
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||||
fixup (
|
_dl_fixup (
|
||||||
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
# ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
||||||
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
||||||
# endif
|
# endif
|
||||||
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
||||||
without the `__unbounded' qualifier. */
|
without the `__unbounded' qualifier. */
|
||||||
struct link_map *__unbounded l, ElfW(Word) reloc_offset)
|
struct link_map *__unbounded l, ElfW(Word) reloc_offset)
|
||||||
{
|
{
|
||||||
const ElfW(Sym) *const symtab
|
const ElfW(Sym) *const symtab
|
||||||
= (const void *) D_PTR (l, l_info[DT_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)
|
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
||||||
{
|
{
|
||||||
const struct r_found_version *version = NULL;
|
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)
|
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||||
{
|
{
|
||||||
@ -91,8 +89,6 @@ fixup (
|
|||||||
version = &l->l_versions[ndx];
|
version = &l->l_versions[ndx];
|
||||||
if (version->hash == 0)
|
if (version->hash == 0)
|
||||||
version = NULL;
|
version = NULL;
|
||||||
else
|
|
||||||
flags = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
|
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
|
/* We already found the symbol. The module (and therefore its load
|
||||||
address) is also known. */
|
address) is also known. */
|
||||||
value = l->l_addr + sym->st_value;
|
value = l->l_addr + sym->st_value;
|
||||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
|
||||||
result = l;
|
result = l;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And now perhaps the relocation addend. */
|
/* And now perhaps the relocation addend. */
|
||||||
@ -127,45 +121,45 @@ fixup (
|
|||||||
|
|
||||||
#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
|
#if !defined PROF && !defined ELF_MACHINE_NO_PLT && !__BOUNDED_POINTERS__
|
||||||
|
|
||||||
static ElfW(Addr)
|
ElfW(Addr)
|
||||||
__attribute ((used, noinline)) ARCH_FIXUP_ATTRIBUTE
|
__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
|
||||||
profile_fixup (
|
_dl_profile_fixup (
|
||||||
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
#ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
|
||||||
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
ELF_MACHINE_RUNTIME_FIXUP_ARGS,
|
||||||
#endif
|
#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);
|
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
|
/* This is the address in the array where we store the result of previous
|
||||||
relocations. */
|
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)
|
if (value == 0)
|
||||||
{
|
{
|
||||||
/* This is the first time we have to relocate this object. */
|
/* This is the first time we have to relocate this object. */
|
||||||
const ElfW(Sym) *const symtab
|
const ElfW(Sym) *const symtab
|
||||||
= (const void *) D_PTR (l, l_info[DT_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 PLTREL *const reloc
|
||||||
= (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
|
= (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. */
|
/* Sanity check that we're really looking at a PLT relocation. */
|
||||||
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
|
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
|
||||||
|
|
||||||
/* Look up the target symbol. If the symbol is marked STV_PROTECTED
|
/* Look up the target symbol. If the symbol is marked STV_PROTECTED
|
||||||
don't look in the global scope. */
|
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;
|
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)
|
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||||
{
|
{
|
||||||
@ -175,11 +169,9 @@ profile_fixup (
|
|||||||
version = &l->l_versions[ndx];
|
version = &l->l_versions[ndx];
|
||||||
if (version->hash == 0)
|
if (version->hash == 0)
|
||||||
version = NULL;
|
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,
|
l->l_scope, version,
|
||||||
ELF_RTYPE_CLASS_PLT,
|
ELF_RTYPE_CLASS_PLT,
|
||||||
DL_LOOKUP_ADD_DEPENDENCY, NULL);
|
DL_LOOKUP_ADD_DEPENDENCY, NULL);
|
||||||
@ -187,25 +179,185 @@ profile_fixup (
|
|||||||
/* Currently result contains the base load address (or link map)
|
/* Currently result contains the base load address (or link map)
|
||||||
of the object that defines sym. Now add in the symbol
|
of the object that defines sym. Now add in the symbol
|
||||||
offset. */
|
offset. */
|
||||||
value = (sym ? LOOKUP_VALUE_ADDRESS (result) + sym->st_value : 0);
|
value = (defsym != NULL
|
||||||
|
? LOOKUP_VALUE_ADDRESS (result) + defsym->st_value : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We already found the symbol. The module (and therefore its load
|
/* We already found the symbol. The module (and therefore its load
|
||||||
address) is also known. */
|
address) is also known. */
|
||||||
value = l->l_addr + sym->st_value;
|
value = l->l_addr + refsym->st_value;
|
||||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
|
||||||
result = l;
|
result = l;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
/* And now perhaps the relocation addend. */
|
/* And now perhaps the relocation addend. */
|
||||||
value = elf_machine_plt_value (l, reloc, value);
|
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. */
|
/* Store the result for later runs. */
|
||||||
if (__builtin_expect (! GLRO(dl_bind_not), 1))
|
if (__builtin_expect (! GLRO(dl_bind_not), 1))
|
||||||
*resultp = value;
|
*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);
|
(*mcount_fct) (retaddr, value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@ -214,9 +366,45 @@ profile_fixup (
|
|||||||
#endif /* PROF && ELF_MACHINE_NO_PLT */
|
#endif /* PROF && ELF_MACHINE_NO_PLT */
|
||||||
|
|
||||||
|
|
||||||
/* This macro is defined in dl-machine.h to define the entry point called
|
#include <stdio.h>
|
||||||
by the PLT. The `fixup' function above does the real work, but a little
|
void
|
||||||
more twiddling is needed to get the stack right and jump to the address
|
ARCH_FIXUP_ATTRIBUTE
|
||||||
finally resolved. */
|
_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)
|
if (ref != NULL)
|
||||||
{
|
{
|
||||||
|
void *value;
|
||||||
|
|
||||||
#if defined USE_TLS && defined SHARED
|
#if defined USE_TLS && defined SHARED
|
||||||
if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
|
if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
|
||||||
/* The found symbol is a thread-local storage variable.
|
/* The found symbol is a thread-local storage variable.
|
||||||
Return the address for to the current thread. */
|
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
|
#endif
|
||||||
|
|
||||||
return DL_SYMBOL_ADDRESS (result, ref);
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef RESOLVE
|
#ifdef RESOLVE_MAP
|
||||||
/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
|
/* 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
|
ElfW(Addr), because not all architectures can assume that the
|
||||||
relocated address is properly aligned, whereas the compiler is
|
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_*. */
|
/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
|
||||||
#ifndef RESOLVE
|
#ifndef RESOLVE_MAP
|
||||||
static
|
static
|
||||||
#else
|
#else
|
||||||
auto
|
auto
|
||||||
@ -199,7 +199,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RESOLVE
|
#ifdef RESOLVE_MAP
|
||||||
|
|
||||||
# ifdef RTLD_BOOTSTRAP
|
# ifdef RTLD_BOOTSTRAP
|
||||||
# define ELF_DURING_STARTUP (1)
|
# 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
|
/* Data structure for communication from the run-time dynamic linker for
|
||||||
loaded ELF shared objects.
|
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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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
|
#define _ElfW_1(e,w,t) e##w##t
|
||||||
|
|
||||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||||
|
#include <bits/link.h>
|
||||||
|
|
||||||
/* Rendezvous structure used by the run-time dynamic linker to communicate
|
/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||||
details of shared object loading to the debugger. If the executable's
|
details of shared object loading to the debugger. If the executable's
|
||||||
@ -94,6 +95,47 @@ struct link_map
|
|||||||
|
|
||||||
#ifdef __USE_GNU
|
#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
|
struct dl_phdr_info
|
||||||
{
|
{
|
||||||
ElfW(Addr) dlpi_addr;
|
ElfW(Addr) dlpi_addr;
|
||||||
@ -114,9 +156,28 @@ struct dl_phdr_info
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
extern int dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
|
extern int dl_iterate_phdr (int (*__callback) (struct dl_phdr_info *,
|
||||||
size_t size, void *data),
|
size_t, void *),
|
||||||
void *data);
|
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
|
__END_DECLS
|
||||||
|
|
||||||
|
541
elf/rtld.c
541
elf/rtld.c
@ -79,6 +79,13 @@ INTDEF(_dl_argv)
|
|||||||
/* Nonzero if we were run directly. */
|
/* Nonzero if we were run directly. */
|
||||||
unsigned int _dl_skip_args attribute_relro attribute_hidden;
|
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
|
#ifndef HAVE_INLINED_SYSCALLS
|
||||||
/* Set nonzero during loading and initialization of executable and
|
/* Set nonzero during loading and initialization of executable and
|
||||||
libraries, cleared before the executable's entry point runs. This
|
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,
|
._dl_fpu_control = _FPU_DEFAULT,
|
||||||
|
|
||||||
/* Function pointers. */
|
/* 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_debug_printf = _dl_debug_printf,
|
||||||
._dl_catch_error = _dl_catch_error,
|
._dl_catch_error = _dl_catch_error,
|
||||||
._dl_signal_error = _dl_signal_error,
|
._dl_signal_error = _dl_signal_error,
|
||||||
._dl_start_profile = _dl_start_profile,
|
|
||||||
._dl_mcount = _dl_mcount_internal,
|
._dl_mcount = _dl_mcount_internal,
|
||||||
._dl_lookup_symbol_x = _dl_lookup_symbol_x,
|
._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
|
/* If we would use strong_alias here the compiler would see a
|
||||||
non-hidden definition. This would undo the effect of the previous
|
non-hidden definition. This would undo the effect of the previous
|
||||||
@ -472,7 +468,7 @@ _dl_start (void *arg)
|
|||||||
while (remaining-- > 0)
|
while (remaining-- > 0)
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
/* Install the pointer to the dtv. */
|
/* Install the pointer to the dtv. */
|
||||||
|
|
||||||
@ -514,6 +510,7 @@ _dl_start (void *arg)
|
|||||||
data access using the global offset table. */
|
data access using the global offset table. */
|
||||||
|
|
||||||
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
|
ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0);
|
||||||
|
bootstrap_map.l_relocated = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Please note that we don't allow profiling of this object and
|
/* Please note that we don't allow profiling of this object and
|
||||||
@ -566,6 +563,19 @@ struct map_args
|
|||||||
struct link_map *map;
|
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. */
|
/* Arguments to version_check_doit. */
|
||||||
struct version_check_args
|
struct version_check_args
|
||||||
{
|
{
|
||||||
@ -590,6 +600,28 @@ map_doit (void *a)
|
|||||||
LM_ID_BASE);
|
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
|
static void
|
||||||
version_check_doit (void *a)
|
version_check_doit (void *a)
|
||||||
{
|
{
|
||||||
@ -648,6 +680,80 @@ match_version (const char *string, struct link_map *map)
|
|||||||
return 0;
|
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
|
#ifdef _LIBC_REENTRANT
|
||||||
/* _dl_error_catch_tsd points to this for the single-threaded case.
|
/* _dl_error_catch_tsd points to this for the single-threaded case.
|
||||||
It's reset by the thread library for multithreaded programs. */
|
It's reset by the thread library for multithreaded programs. */
|
||||||
@ -702,7 +808,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
|||||||
hp_timing_t diff;
|
hp_timing_t diff;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
void *tcbp;
|
void *tcbp = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _LIBC_REENTRANT
|
#ifdef _LIBC_REENTRANT
|
||||||
@ -826,6 +932,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
|||||||
objects. */
|
objects. */
|
||||||
_dl_init_paths (library_path);
|
_dl_init_paths (library_path);
|
||||||
|
|
||||||
|
|
||||||
/* The initialization of _dl_stack_flags done below assumes the
|
/* The initialization of _dl_stack_flags done below assumes the
|
||||||
executable's PT_GNU_STACK may have been honored by the kernel, and
|
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
|
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.
|
/* Create a link_map for the executable itself.
|
||||||
This will be what dlopen on "" returns. */
|
This will be what dlopen on "" returns. */
|
||||||
_dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
|
main_map
|
||||||
main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
= _dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
|
||||||
if (main_map == NULL)
|
assert (main_map != NULL);
|
||||||
_dl_fatal_printf ("cannot allocate memory for link map\n");
|
assert (main_map == GL(dl_ns)[LM_ID_BASE]._ns_loaded);
|
||||||
main_map->l_phdr = phdr;
|
main_map->l_phdr = phdr;
|
||||||
main_map->l_phnum = phnum;
|
main_map->l_phnum = phnum;
|
||||||
main_map->l_entry = *user_entry;
|
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;
|
main_map->l_text_end = allocend;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#ifdef USE_TLS
|
|
||||||
case PT_TLS:
|
case PT_TLS:
|
||||||
|
#ifdef USE_TLS
|
||||||
if (ph->p_memsz > 0)
|
if (ph->p_memsz > 0)
|
||||||
{
|
{
|
||||||
/* Note that in the case the dynamic linker we duplicate work
|
/* 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. */
|
/* This image gets the ID one. */
|
||||||
GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
|
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
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
case PT_GNU_STACK:
|
case PT_GNU_STACK:
|
||||||
GL(dl_stack_flags) = ph->p_flags;
|
GL(dl_stack_flags) = ph->p_flags;
|
||||||
break;
|
break;
|
||||||
@ -1045,6 +1157,26 @@ of this helper program; chances are you did not intend to run this program.\n\
|
|||||||
else
|
else
|
||||||
assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
|
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)
|
if (! rtld_is_main)
|
||||||
{
|
{
|
||||||
/* Extract the contents of the dynamic section for easy access. */
|
/* 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. */
|
objects. */
|
||||||
_dl_init_paths (library_path);
|
_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
|
/* 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
|
name. Note that at this point the global chain of link maps contains
|
||||||
exactly one element, which is pointed to by dl_loaded. */
|
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_phdr = rtld_phdr;
|
||||||
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
|
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
|
||||||
|
|
||||||
|
|
||||||
/* PT_GNU_RELRO is usually the last phdr. */
|
/* PT_GNU_RELRO is usually the last phdr. */
|
||||||
size_t cnt = rtld_ehdr->e_phnum;
|
size_t cnt = rtld_ehdr->e_phnum;
|
||||||
while (cnt-- > 0)
|
while (cnt-- > 0)
|
||||||
@ -1111,6 +1248,204 @@ of this helper program; chances are you did not intend to run this program.\n\
|
|||||||
break;
|
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
|
/* We have two ways to specify objects to preload: via environment
|
||||||
variable and via the file /etc/ld.so.preload. The latter can also
|
variable and via the file /etc/ld.so.preload. The latter can also
|
||||||
be used when security is enabled. */
|
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)
|
&& ph->p_vaddr + ph->p_memsz >= l->l_text_end)
|
||||||
l->l_text_end = ph->p_vaddr + ph->p_memsz;
|
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_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso);
|
||||||
l->l_addr = l->l_map_start - l->l_addr;
|
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
|
#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
|
/* We do not initialize any of the TLS functionality unless any of the
|
||||||
initial modules uses TLS. This makes dynamic loading of modules with
|
initial modules uses TLS. This makes dynamic loading of modules with
|
||||||
TLS impossible, but to support it requires either eagerly doing setup
|
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
|
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
|
used. Trying to do it lazily is too hairy to try when there could be
|
||||||
multiple threads (from a non-TLS-using libpthread). */
|
multiple threads (from a non-TLS-using libpthread). */
|
||||||
if (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0)
|
bool was_tls_init_tp_called = tls_init_tp_called;
|
||||||
{
|
if (tcbp == NULL && (!TLS_INIT_TP_EXPENSIVE || GL(dl_tls_max_dtv_idx) > 0))
|
||||||
struct link_map *l;
|
tcbp = init_tls ();
|
||||||
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);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (__builtin_expect (mode, normal) != normal)
|
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;
|
struct link_map *l = main_map;
|
||||||
|
|
||||||
@ -1813,8 +2087,6 @@ cannot allocate TLS data structures for initial thread");
|
|||||||
|
|
||||||
if (prelinked)
|
if (prelinked)
|
||||||
{
|
{
|
||||||
struct link_map *l;
|
|
||||||
|
|
||||||
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
|
if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
|
||||||
{
|
{
|
||||||
ElfW(Rela) *conflict, *conflictend;
|
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. */
|
/* 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;
|
l->l_relocated = 1;
|
||||||
if (l->l_relro_size)
|
if (l->l_relro_size)
|
||||||
_dl_protect_relro (l);
|
_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 ();
|
_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
|
the dynamic linker out of order because it has no copy relocs (we
|
||||||
know that because it is self-contained). */
|
know that because it is self-contained). */
|
||||||
|
|
||||||
struct link_map *l;
|
|
||||||
int consider_profiling = GLRO(dl_profile) != NULL;
|
int consider_profiling = GLRO(dl_profile) != NULL;
|
||||||
#ifndef HP_TIMING_NONAVAIL
|
#ifndef HP_TIMING_NONAVAIL
|
||||||
hp_timing_t start;
|
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. */
|
/* If we are profiling we also must do lazy reloaction. */
|
||||||
GLRO(dl_lazy) |= consider_profiling;
|
GLRO(dl_lazy) |= consider_profiling;
|
||||||
|
|
||||||
l = main_map;
|
struct link_map *l = main_map;
|
||||||
while (l->l_next)
|
while (l->l_next)
|
||||||
l = 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),
|
_dl_relocate_object (l, l->l_scope, GLRO(dl_lazy),
|
||||||
consider_profiling);
|
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;
|
l = l->l_prev;
|
||||||
}
|
}
|
||||||
while (l);
|
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.
|
/* There was an explicit ref to the dynamic linker as a shared lib.
|
||||||
Re-relocate ourselves with user-controlled symbol definitions. */
|
Re-relocate ourselves with user-controlled symbol definitions. */
|
||||||
HP_TIMING_NOW (start);
|
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);
|
_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
|
||||||
HP_TIMING_NOW (stop);
|
HP_TIMING_NOW (stop);
|
||||||
HP_TIMING_DIFF (add, start, stop);
|
HP_TIMING_DIFF (add, start, stop);
|
||||||
@ -1931,6 +2212,9 @@ cannot allocate TLS data structures for initial thread");
|
|||||||
#ifdef USE_TLS
|
#ifdef USE_TLS
|
||||||
if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD || !TLS_INIT_TP_EXPENSIVE)
|
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
|
/* Now that we have completed relocation, the initializer data
|
||||||
for the TLS blocks has its final values and we can copy them
|
for the TLS blocks has its final values and we can copy them
|
||||||
into the main thread's TLS area, which we allocated above. */
|
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
|
/* And finally install it for the main thread. If ld.so itself uses
|
||||||
TLS we know the thread pointer was initialized earlier. */
|
TLS we know the thread pointer was initialized earlier. */
|
||||||
const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
|
if (! tls_init_tp_called)
|
||||||
if (__builtin_expect (lossage != NULL, 0))
|
{
|
||||||
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
|
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
|
else
|
||||||
#endif
|
#endif
|
||||||
NONTLS_INIT_TP;
|
NONTLS_INIT_TP;
|
||||||
|
|
||||||
/* Notify the debugger that all objects are now mapped in. */
|
#ifdef SHARED
|
||||||
r->r_state = RT_ADD;
|
/* 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 ();
|
_dl_debug_state ();
|
||||||
|
|
||||||
#ifndef MAP_COPY
|
#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.
|
/* Process all environments variables the dynamic linker must recognize.
|
||||||
Since all of them start with `LD_' we are a bit smarter while finding
|
Since all of them start with `LD_' we are a bit smarter while finding
|
||||||
all the entries. */
|
all the entries. */
|
||||||
@ -2121,7 +2457,12 @@ process_envvars (enum mode *modep)
|
|||||||
case 5:
|
case 5:
|
||||||
/* Debugging of the dynamic linker? */
|
/* Debugging of the dynamic linker? */
|
||||||
if (memcmp (envline, "DEBUG", 5) == 0)
|
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;
|
break;
|
||||||
|
|
||||||
case 7:
|
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_SPROF 0x40000000
|
||||||
#define __RTLD_OPENEXEC 0x20000000
|
#define __RTLD_OPENEXEC 0x20000000
|
||||||
#define __RTLD_CALLMAP 0x10000000
|
#define __RTLD_CALLMAP 0x10000000
|
||||||
|
#define __RTLD_AUDIT 0x08000000
|
||||||
|
|
||||||
#define __LM_ID_CALLER -2
|
#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. */
|
/* Now define the internal interfaces. */
|
||||||
|
|
||||||
#define __libc_dlopen(name) \
|
#define __libc_dlopen(name) \
|
||||||
@ -29,18 +44,8 @@ extern int _dl_addr (const void *address, Dl_info *info,
|
|||||||
libc_hidden_proto (_dl_addr)
|
libc_hidden_proto (_dl_addr)
|
||||||
#endif
|
#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. */
|
/* Close an object previously opened by _dl_open. */
|
||||||
extern void _dl_close (void *map)
|
extern void _dl_close (void *map) attribute_hidden;
|
||||||
internal_function;
|
|
||||||
libc_hidden_proto (_dl_close)
|
|
||||||
|
|
||||||
/* Look up NAME in shared object HANDLE (which may be RTLD_DEFAULT or
|
/* Look up NAME in shared object HANDLE (which may be RTLD_DEFAULT or
|
||||||
RTLD_NEXT). WHO is the calling function, for RTLD_NEXT. Returns
|
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/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||||
#include <bits/link.h>
|
#include <bits/link.h>
|
||||||
|
#include <bits/linkmap.h>
|
||||||
#include <dl-lookupcfg.h>
|
#include <dl-lookupcfg.h>
|
||||||
#include <tls.h> /* Defines USE_TLS. */
|
#include <tls.h> /* Defines USE_TLS. */
|
||||||
|
|
||||||
@ -199,6 +200,10 @@ struct link_map
|
|||||||
should be called on this link map
|
should be called on this link map
|
||||||
when relocation finishes. */
|
when relocation finishes. */
|
||||||
unsigned int l_used:1; /* Nonzero if the DSO is used. */
|
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. */
|
/* Array with version names. */
|
||||||
unsigned int l_nversions;
|
unsigned int l_nversions;
|
||||||
struct r_found_version *l_versions;
|
struct r_found_version *l_versions;
|
||||||
@ -207,7 +212,14 @@ struct link_map
|
|||||||
struct r_search_path_struct l_rpath_dirs;
|
struct r_search_path_struct l_rpath_dirs;
|
||||||
|
|
||||||
/* Collected results of relocation while profiling. */
|
/* 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. */
|
/* Pointer to the version information if available. */
|
||||||
ElfW(Versym) *l_versyms;
|
ElfW(Versym) *l_versyms;
|
||||||
@ -263,11 +275,7 @@ struct link_map
|
|||||||
{
|
{
|
||||||
const ElfW(Sym) *sym;
|
const ElfW(Sym) *sym;
|
||||||
int type_class;
|
int type_class;
|
||||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
|
||||||
struct link_map *value;
|
struct link_map *value;
|
||||||
#else
|
|
||||||
ElfW(Addr) value;
|
|
||||||
#endif
|
|
||||||
const ElfW(Sym) *ret;
|
const ElfW(Sym) *ret;
|
||||||
} l_lookup_cache;
|
} l_lookup_cache;
|
||||||
|
|
||||||
@ -297,8 +305,65 @@ struct link_map
|
|||||||
done. */
|
done. */
|
||||||
ElfW(Addr) l_relro_addr;
|
ElfW(Addr) l_relro_addr;
|
||||||
size_t l_relro_size;
|
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
|
struct dl_phdr_info
|
||||||
{
|
{
|
||||||
ElfW(Addr) dlpi_addr;
|
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>
|
2004-12-27 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
* init.c (__pthread_initialize_minimal_internal): Use __sigemptyset.
|
* init.c (__pthread_initialize_minimal_internal): Use __sigemptyset.
|
||||||
|
@ -920,7 +920,8 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
/* 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. */
|
/* Initialize the memory. */
|
||||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
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.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -23,6 +23,7 @@
|
|||||||
# include <dl-sysdep.h>
|
# include <dl-sysdep.h>
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
|
|
||||||
@ -30,7 +31,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
#else /* __ASSEMBLER__ */
|
#else /* __ASSEMBLER__ */
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <dl-sysdep.h>
|
#include <dl-sysdep.h>
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -32,7 +33,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Definition for thread-local data handling. nptl/IA-64 version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <dl-sysdep.h>
|
#include <dl-sysdep.h>
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -32,7 +33,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Definition for thread-local data handling. NPTL/PowerPC version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -23,6 +23,7 @@
|
|||||||
# include <dl-sysdep.h>
|
# include <dl-sysdep.h>
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
|
|
||||||
@ -30,7 +31,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
#else /* __ASSEMBLER__ */
|
#else /* __ASSEMBLER__ */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Definition for thread-local data handling. NPTL/s390 version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <dl-sysdep.h>
|
#include <dl-sysdep.h>
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -32,7 +33,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Definition for thread-local data handling. NPTL/SH version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -23,6 +23,7 @@
|
|||||||
# include <dl-sysdep.h>
|
# include <dl-sysdep.h>
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
|
|
||||||
@ -30,7 +31,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Definitions for thread-local data handling. NPTL/sparc version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <dl-sysdep.h>
|
#include <dl-sysdep.h>
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -31,7 +32,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Definition for thread-local data handling. nptl/x86_64 version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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. */
|
#include <asm/prctl.h> /* For ARCH_SET_FS. */
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
# include <stdbool.h>
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
@ -31,7 +32,11 @@
|
|||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
void *pointer;
|
struct
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
bool is_static;
|
||||||
|
} pointer;
|
||||||
} dtv_t;
|
} 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
|
#error "Architecture-specific definition needed."
|
||||||
{
|
|
||||||
/* empty by default */
|
|
||||||
};
|
|
||||||
|
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.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
/* Some platforms need more information from the symbol lookup function
|
/* Nothing special. */
|
||||||
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
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -18,6 +18,8 @@
|
|||||||
02111-1307 USA. */
|
02111-1307 USA. */
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libintl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -116,10 +118,9 @@ void
|
|||||||
internal_function
|
internal_function
|
||||||
_dl_determine_tlsoffset (void)
|
_dl_determine_tlsoffset (void)
|
||||||
{
|
{
|
||||||
struct dtv_slotinfo *slotinfo;
|
|
||||||
size_t max_align = TLS_TCB_ALIGN;
|
size_t max_align = TLS_TCB_ALIGN;
|
||||||
size_t offset, freetop = 0, freebottom = 0;
|
size_t freetop = 0;
|
||||||
size_t cnt;
|
size_t freebottom = 0;
|
||||||
|
|
||||||
/* The first element of the dtv slot info list is allocated. */
|
/* The first element of the dtv slot info list is allocated. */
|
||||||
assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
|
assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
|
||||||
@ -127,7 +128,7 @@ _dl_determine_tlsoffset (void)
|
|||||||
dl_tls_dtv_slotinfo_list list. */
|
dl_tls_dtv_slotinfo_list list. */
|
||||||
assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
|
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
|
/* Determining the offset of the various parts of the static TLS
|
||||||
block has several dependencies. In addition we have to work
|
block has several dependencies. In addition we have to work
|
||||||
@ -159,9 +160,9 @@ _dl_determine_tlsoffset (void)
|
|||||||
|
|
||||||
# if TLS_TCB_AT_TP
|
# if TLS_TCB_AT_TP
|
||||||
/* We simply start with zero. */
|
/* 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);
|
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
|
||||||
|
|
||||||
@ -206,9 +207,9 @@ _dl_determine_tlsoffset (void)
|
|||||||
+ TLS_TCB_SIZE);
|
+ TLS_TCB_SIZE);
|
||||||
# elif TLS_DTV_AT_TP
|
# elif TLS_DTV_AT_TP
|
||||||
/* The TLS blocks start right after the TCB. */
|
/* 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);
|
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)
|
if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
|
||||||
{
|
{
|
||||||
slotinfo[cnt].map->l_tls_offset = off - firstbyte;
|
slotinfo[cnt].map->l_tls_offset = off - firstbyte;
|
||||||
freebottom = off + slotinfo[cnt].map->l_tls_blocksize
|
freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
|
||||||
- firstbyte;
|
- firstbyte);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,14 +358,14 @@ _dl_allocate_tls_storage (void)
|
|||||||
|
|
||||||
/* Clear the TCB data structure. We can't ask the caller (i.e.
|
/* 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. */
|
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
|
# elif TLS_DTV_AT_TP
|
||||||
result = (char *) result + size - GL(dl_tls_static_size);
|
result = (char *) result + size - GL(dl_tls_static_size);
|
||||||
|
|
||||||
/* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
|
/* 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
|
We can't ask the caller (i.e. libpthread) to do it, because we will
|
||||||
initialize the DTV et al. */
|
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);
|
TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
@ -388,10 +389,11 @@ _dl_allocate_tls_init (void *result)
|
|||||||
dtv_t *dtv = GET_DTV (result);
|
dtv_t *dtv = GET_DTV (result);
|
||||||
struct dtv_slotinfo_list *listp;
|
struct dtv_slotinfo_list *listp;
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
|
size_t maxgen = 0;
|
||||||
|
|
||||||
/* We have to look prepare the dtv for all currently loaded
|
/* We have to prepare the dtv for all currently loaded modules using
|
||||||
modules using TLS. For those which are dynamically loaded we
|
TLS. For those which are dynamically loaded we add the values
|
||||||
add the values indicating deferred allocation. */
|
indicating deferred allocation. */
|
||||||
listp = GL(dl_tls_dtv_slotinfo_list);
|
listp = GL(dl_tls_dtv_slotinfo_list);
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -411,11 +413,16 @@ _dl_allocate_tls_init (void *result)
|
|||||||
/* Unused entry. */
|
/* Unused entry. */
|
||||||
continue;
|
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)
|
if (map->l_tls_offset == NO_TLS_OFFSET)
|
||||||
{
|
{
|
||||||
/* For dynamically loaded modules we simply store
|
/* For dynamically loaded modules we simply store
|
||||||
the value indicating deferred allocation. */
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +438,8 @@ _dl_allocate_tls_init (void *result)
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Copy the initialization image and clear the BSS part. */
|
/* 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,
|
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||||
map->l_tls_initimage_size), '\0',
|
map->l_tls_initimage_size), '\0',
|
||||||
map->l_tls_blocksize - map->l_tls_initimage_size);
|
map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||||
@ -445,6 +453,9 @@ _dl_allocate_tls_init (void *result)
|
|||||||
assert (listp != NULL);
|
assert (listp != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The DTV version is up-to-date now. */
|
||||||
|
dtv[0].counter = maxgen;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
rtld_hidden_def (_dl_allocate_tls_init)
|
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);
|
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]. */
|
/* The array starts with dtv[-1]. */
|
||||||
#ifdef SHARED
|
#ifdef SHARED
|
||||||
if (dtv != GL(dl_initial_dtv))
|
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
|
/* The generic dynamic and local dynamic model cannot be used in
|
||||||
statically linked applications. */
|
statically linked applications. */
|
||||||
void *
|
void *
|
||||||
@ -534,156 +704,9 @@ __tls_get_addr (GET_ADDR_ARGS)
|
|||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
|
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
|
||||||
{
|
the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
|
||||||
struct dtv_slotinfo_list *listp;
|
|
||||||
size_t idx;
|
|
||||||
|
|
||||||
/* The global dl_tls_dtv_slotinfo array contains for each module
|
p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||||
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;
|
|
||||||
|
|
||||||
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
|
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
|
||||||
{
|
{
|
||||||
@ -703,11 +726,74 @@ __tls_get_addr (GET_ADDR_ARGS)
|
|||||||
the_map = listp->slotinfo[idx].map;
|
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;
|
return (char *) p + GET_ADDR_OFFSET;
|
||||||
}
|
}
|
||||||
# endif
|
# 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 */
|
#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
|
most architectures the entry is already relocated - but for some not
|
||||||
and we need to relocate at access time. */
|
and we need to relocate at access time. */
|
||||||
#ifdef DL_RO_DYN_SECTION
|
#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
|
#else
|
||||||
# define D_PTR(map,i) map->i->d_un.d_ptr
|
# define D_PTR(map, i) (map)->i->d_un.d_ptr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* On some platforms more information than just the address of the symbol
|
/* Result of the lookup functions and how to retrieve the base address. */
|
||||||
is needed from the lookup functions. In this case we return the whole
|
|
||||||
link map. */
|
|
||||||
#ifdef DL_LOOKUP_RETURNS_MAP
|
|
||||||
typedef struct link_map *lookup_t;
|
typedef struct link_map *lookup_t;
|
||||||
# define LOOKUP_VALUE(map) map
|
# define LOOKUP_VALUE(map) map
|
||||||
# define LOOKUP_VALUE_ADDRESS(map) (map ? map->l_addr : 0)
|
# 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
|
|
||||||
|
|
||||||
/* on some architectures a pointer to a function is not just a pointer
|
/* on some architectures a pointer to a function is not just a pointer
|
||||||
to the actual code of the function but rather an architecture
|
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. */
|
/* 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)
|
extern int _dl_name_match_p (const char *__name, struct link_map *__map)
|
||||||
internal_function;
|
internal_function;
|
||||||
@ -224,7 +265,7 @@ struct rtld_global
|
|||||||
#endif
|
#endif
|
||||||
EXTERN struct link_namespaces
|
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;
|
struct link_map *_ns_loaded;
|
||||||
/* Number of object in the _dl_loaded list. */
|
/* Number of object in the _dl_loaded list. */
|
||||||
unsigned int _ns_nloaded;
|
unsigned int _ns_nloaded;
|
||||||
@ -277,8 +318,12 @@ struct rtld_global
|
|||||||
EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
|
EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
|
||||||
#endif
|
#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;
|
EXTERN struct link_map _dl_rtld_map;
|
||||||
|
#ifdef SHARED
|
||||||
|
struct auditstate audit_data[DL_NNS];
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined SHARED && defined _LIBC_REENTRANT \
|
#if defined SHARED && defined _LIBC_REENTRANT \
|
||||||
&& defined __rtld_lock_default_lock_recursive
|
&& defined __rtld_lock_default_lock_recursive
|
||||||
@ -311,6 +356,7 @@ struct rtld_global
|
|||||||
struct dtv_slotinfo
|
struct dtv_slotinfo
|
||||||
{
|
{
|
||||||
size_t gen;
|
size_t gen;
|
||||||
|
bool is_static;
|
||||||
struct link_map *map;
|
struct link_map *map;
|
||||||
} slotinfo[0];
|
} slotinfo[0];
|
||||||
} *_dl_tls_dtv_slotinfo_list;
|
} *_dl_tls_dtv_slotinfo_list;
|
||||||
@ -483,32 +529,12 @@ struct rtld_global_ro
|
|||||||
call the function instead of going through the PLT. The result
|
call the function instead of going through the PLT. The result
|
||||||
is that we can avoid exporting the functions and we do not jump
|
is that we can avoid exporting the functions and we do not jump
|
||||||
PLT relocations in libc.so. */
|
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 *, ...)
|
void (*_dl_debug_printf) (const char *, ...)
|
||||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||||
int (internal_function *_dl_catch_error) (const char **, const char **,
|
int (internal_function *_dl_catch_error) (const char **, const char **,
|
||||||
void (*) (void *), void *);
|
void (*) (void *), void *);
|
||||||
void (internal_function *_dl_signal_error) (int, const char *, const char *,
|
void (internal_function *_dl_signal_error) (int, const char *, const char *,
|
||||||
const char *);
|
const char *);
|
||||||
void (internal_function *_dl_start_profile) (void);
|
|
||||||
void (*_dl_mcount) (ElfW(Addr) frompc, ElfW(Addr) selfpc);
|
void (*_dl_mcount) (ElfW(Addr) frompc, ElfW(Addr) selfpc);
|
||||||
lookup_t (internal_function *_dl_lookup_symbol_x) (const char *,
|
lookup_t (internal_function *_dl_lookup_symbol_x) (const char *,
|
||||||
struct link_map *,
|
struct link_map *,
|
||||||
@ -518,7 +544,13 @@ struct rtld_global_ro
|
|||||||
int, int,
|
int, int,
|
||||||
struct link_map *);
|
struct link_map *);
|
||||||
int (*_dl_check_caller) (const void *, enum allowmask);
|
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__
|
# define __rtld_global_attribute__
|
||||||
# ifdef IS_IN_rtld
|
# 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)
|
extern int _dl_check_caller (const void *caller, enum allowmask mask)
|
||||||
attribute_hidden;
|
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
|
__END_DECLS
|
||||||
|
|
||||||
#endif /* ldsodefs.h */
|
#endif /* ldsodefs.h */
|
||||||
|
@ -80,6 +80,10 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
|||||||
void *__unbounded stack_end)
|
void *__unbounded stack_end)
|
||||||
__attribute__ ((noreturn));
|
__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
|
STATIC int
|
||||||
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||||
int argc, char *__unbounded *__unbounded ubp_av,
|
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);
|
__libc_init_first (argc, argv, __environ);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Register the destructor of the program, if any. */
|
|
||||||
if (fini)
|
|
||||||
__cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
|
|
||||||
|
|
||||||
#ifndef SHARED
|
#ifndef SHARED
|
||||||
/* Some security at this point. Prevent starting a SUID binary where
|
/* Some security at this point. Prevent starting a SUID binary where
|
||||||
the standard file descriptors are not opened. We have to do this
|
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
|
#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
|
#ifdef SHARED
|
||||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||||
GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
|
GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Initialization code for TLS in statically linked application.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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. */
|
/* Initialize the TLS block. */
|
||||||
# if TLS_TCB_AT_TP
|
# if TLS_TCB_AT_TP
|
||||||
static_dtv[2].pointer = ((char *) tlsblock + tcb_offset
|
static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
|
||||||
- roundup (memsz, align ?: 1));
|
- roundup (memsz, align ?: 1));
|
||||||
static_map.l_tls_offset = roundup (memsz, align ?: 1);
|
static_map.l_tls_offset = roundup (memsz, align ?: 1);
|
||||||
# elif TLS_DTV_AT_TP
|
# 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;
|
static_map.l_tls_offset = tcb_offset;
|
||||||
# else
|
# else
|
||||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||||
# endif
|
# endif
|
||||||
|
static_dtv[2].pointer.is_static = true;
|
||||||
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
|
/* 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. */
|
/* Install the pointer to the dtv. */
|
||||||
|
|
||||||
|
@ -2,18 +2,19 @@
|
|||||||
all stuffed in a single string which means they have to be terminated
|
all stuffed in a single string which means they have to be terminated
|
||||||
with a '\0' explicitly. */
|
with a '\0' explicitly. */
|
||||||
#define UNSECURE_ENVVARS \
|
#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" \
|
"GCONV_PATH\0" \
|
||||||
"GETCONF_DIR\0" \
|
"GETCONF_DIR\0" \
|
||||||
"HOSTALIASES\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" \
|
"LOCALDOMAIN\0" \
|
||||||
"LOCPATH\0" \
|
"LOCPATH\0" \
|
||||||
"MALLOC_TRACE\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.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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 ELF_FUNCTION_PTR_IS_SPECIAL
|
||||||
#define DL_UNMAP_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))
|
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))
|
||||||
#define DL_DT_FINI_ADDRESS(map, addr) \
|
#define DL_DT_FINI_ADDRESS(map, addr) \
|
||||||
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))
|
((Elf32_Addr)(addr) & 2 ? (addr) : DL_AUTO_FUNCTION_ADDRESS (map, addr))
|
||||||
|
|
||||||
|
@ -1,5 +1,60 @@
|
|||||||
struct link_map_machine
|
/* Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||||
{
|
This file is part of the GNU C Library.
|
||||||
Elf32_Addr plt; /* Address of .plt + 0x16 */
|
|
||||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
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;
|
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
|
/* This is the object we are looking for. Say that we really
|
||||||
want profiling and the timers are started. */
|
want profiling and the timers are started. */
|
||||||
GL(dl_profile_map) = l;
|
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. */
|
destroys the passed register information. */
|
||||||
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
/* GKM FIXME: Fix trampoline to pass bounds so we can do
|
||||||
without the `__unbounded' qualifier. */
|
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,
|
extern ElfW(Addr) _dl_fixup (struct link_map *__unbounded l,
|
||||||
ElfW(Word) reloc_offset)
|
ElfW(Word) reloc_offset)
|
||||||
ARCH_FIXUP_ATTRIBUTE;
|
ARCH_FIXUP_ATTRIBUTE;
|
||||||
static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset,
|
extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
|
||||||
ElfW(Addr) retaddr)
|
ElfW(Word) reloc_offset,
|
||||||
|
ElfW(Addr) retaddr, const void *regs,
|
||||||
|
long int *framesizep)
|
||||||
ARCH_FIXUP_ATTRIBUTE;
|
ARCH_FIXUP_ATTRIBUTE;
|
||||||
# endif
|
# 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
|
#endif
|
||||||
|
|
||||||
/* Mask identifying addresses reserved for the user program,
|
/* 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;
|
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 */
|
#endif /* !dl_machine_h */
|
||||||
|
|
||||||
#ifdef RESOLVE
|
#ifdef RESOLVE_MAP
|
||||||
|
|
||||||
/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
|
/* The i386 never uses Elf32_Rela relocations for the dynamic linker.
|
||||||
Prelinked libraries may use Elf32_Rela though. */
|
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 */
|
#endif /* !RTLD_BOOTSTRAP and have no -z combreloc */
|
||||||
{
|
{
|
||||||
const Elf32_Sym *const refsym = sym;
|
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);
|
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||||
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
||||||
#else
|
#else
|
||||||
@ -549,14 +461,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
|
|||||||
# ifndef RESOLVE_CONFLICT_FIND_MAP
|
# ifndef RESOLVE_CONFLICT_FIND_MAP
|
||||||
const Elf32_Sym *const refsym = sym;
|
const Elf32_Sym *const refsym = sym;
|
||||||
# endif
|
# endif
|
||||||
# ifdef USE_TLS
|
|
||||||
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||||
Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
|
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))
|
switch (ELF32_R_TYPE (reloc->r_info))
|
||||||
{
|
{
|
||||||
@ -692,4 +598,4 @@ elf_machine_lazy_rela (struct link_map *map,
|
|||||||
|
|
||||||
#endif /* !RTLD_BOOTSTRAP */
|
#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.
|
/* 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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
02111-1307 USA. */
|
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 ELF_FUNCTION_PTR_IS_SPECIAL
|
||||||
#define DL_UNMAP_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
|
/* Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||||
struct link_map_machine
|
This file is part of the GNU C Library.
|
||||||
{
|
|
||||||
Elf64_Addr plt; /* Address of .plt + 0x16 */
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
Elf64_Addr gotplt; /* Address of .got + 0x18 */
|
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
|
#else
|
||||||
struct link_map_machine
|
|
||||||
{
|
/* Registers for entry into PLT on x86-64. */
|
||||||
Elf32_Addr plt; /* Address of .plt + 0x16 */
|
typedef float La_x86_64_xmm __attribute__ ((__mode__ (__V4SF__)));
|
||||||
Elf32_Addr gotplt; /* Address of .got + 0x0c */
|
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
|
#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;
|
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
|
/* This is the object we are looking for. Say that we really
|
||||||
want profiling and the timers are started. */
|
want profiling and the timers are started. */
|
||||||
GL(dl_profile_map) = l;
|
GL(dl_profile_map) = l;
|
||||||
@ -130,128 +131,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
|||||||
return lazy;
|
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.
|
/* Initial entry point code for the dynamic linker.
|
||||||
The C function `_dl_start' is the real entry point;
|
The C function `_dl_start' is the real entry point;
|
||||||
its return value is the user program's 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;
|
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 */
|
#endif /* !dl_machine_h */
|
||||||
|
|
||||||
#ifdef RESOLVE
|
#ifdef RESOLVE_MAP
|
||||||
|
|
||||||
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
|
/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
|
||||||
MAP is the object containing the reloc. */
|
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
|
#ifndef RTLD_BOOTSTRAP
|
||||||
const Elf64_Sym *const refsym = sym;
|
const Elf64_Sym *const refsym = sym;
|
||||||
#endif
|
#endif
|
||||||
#if defined USE_TLS && !defined RTLD_BOOTSTRAP
|
#ifndef RTLD_BOOTSTRAP
|
||||||
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
|
||||||
Elf64_Addr value = (sym == NULL ? 0
|
Elf64_Addr value = (sym == NULL ? 0
|
||||||
: (Elf64_Addr) sym_map->l_addr + sym->st_value);
|
: (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);
|
_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