1998-08-27 19:42  Ulrich Drepper  <drepper@cygnus.com>

	* elf/Makefile (distribute): Add dl-origin.h.
	* sysdeps/generic/dl-origin.h: New file.
	* sysdeps/unix/sysv/linux/dl-origin.h: New file.
	* elf/link.h (struct link_map): Add l_origin field.
	* elf/dl-load.c (expand_dynamic_string_token): New function.
	(decompose_path): Remove WHERE argument, take link map pointer instead.
	Call expand_dynamic_string_token instead of local_strdup to make copy
	of rpath.
	(_dl_init_paths): Call decompose_path with correct argument.
	(_dl_map_object_from_fd): Define static is EXTERNAL_MAP_FROM_FD is
	not defined.
	Check EI_OSABI and EI_ABIVERSION fields in header.
	(_dl_map_object): Call decompose_path with correct argument.
	Call expand_dynamic_string_token instead of local_strdup to also
	expand DST.
	* elf/dl-object.c (_dl_new_object): Determine l_origin for all maps
	but the main one.
	* elf/dl-support.c: Define _dl_origin_path.
	* elf/rtld.c: Likewise.  Set _dl_origin_path based on LD_ORIGIN_PATH.

	* elf/dl-close (_dl_close): Free l_name and l_origin.

	* sysdeps/i386/useldt.h (THREAD_GETMEM, THREAD_SETMEM): Use P
	modifier in asm, not c.

	* sysdeps/mach/hurd/Makefile [subdirs==elf]: Define CFLAGS-dl-load.c
	to -DEXTERNAL_MAP_FROM_FD to make _dl_map_object_from_fd extern.
This commit is contained in:
Ulrich Drepper 1998-08-27 20:08:32 +00:00
parent 6075607b9a
commit f787edde1d
12 changed files with 374 additions and 17 deletions

View File

@ -1,3 +1,33 @@
1998-08-27 19:42 Ulrich Drepper <drepper@cygnus.com>
* elf/Makefile (distribute): Add dl-origin.h.
* sysdeps/generic/dl-origin.h: New file.
* sysdeps/unix/sysv/linux/dl-origin.h: New file.
* elf/link.h (struct link_map): Add l_origin field.
* elf/dl-load.c (expand_dynamic_string_token): New function.
(decompose_path): Remove WHERE argument, take link map pointer instead.
Call expand_dynamic_string_token instead of local_strdup to make copy
of rpath.
(_dl_init_paths): Call decompose_path with correct argument.
(_dl_map_object_from_fd): Define static is EXTERNAL_MAP_FROM_FD is
not defined.
Check EI_OSABI and EI_ABIVERSION fields in header.
(_dl_map_object): Call decompose_path with correct argument.
Call expand_dynamic_string_token instead of local_strdup to also
expand DST.
* elf/dl-object.c (_dl_new_object): Determine l_origin for all maps
but the main one.
* elf/dl-support.c: Define _dl_origin_path.
* elf/rtld.c: Likewise. Set _dl_origin_path based on LD_ORIGIN_PATH.
* elf/dl-close (_dl_close): Free l_name and l_origin.
* sysdeps/i386/useldt.h (THREAD_GETMEM, THREAD_SETMEM): Use P
modifier in asm, not c.
* sysdeps/mach/hurd/Makefile [subdirs==elf]: Define CFLAGS-dl-load.c
to -DEXTERNAL_MAP_FROM_FD to make _dl_map_object_from_fd extern.
1998-08-26 17:48 Ulrich Drepper <drepper@cygnus.com>
* elf/dl-close.c (_dl_close): Move map->l_nsearchlist value into local

View File

@ -38,7 +38,7 @@ rtld-routines := rtld $(dl-routines) dl-sysdep dl-environ dl-minimal
distribute = $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
dl-hash.h soinit.c sofini.c ldd.sh.in ldd.bash.in eval.c \
genrtldtbl.awk atomicity.h dl-procinfo.h ldsodefs.h \
dl-librecon.h interp.c sln.c
dl-librecon.h interp.c sln.c dl-origin.h
extra-libs = libdl
extra-libs-others = $(extra-libs)

View File

@ -88,6 +88,11 @@ _dl_close (struct link_map *map)
for (i = 0; i < nsearchlist; ++i)
--list[i]->l_opencount;
if (map->l_origin != NULL)
free ((char *) map->l_origin);
/* The name always is allocated. */
free (map->l_name);
/* Check each element of the search list to see if all references to
it are gone. */
for (i = 0; i < nsearchlist; ++i)

View File

@ -31,6 +31,8 @@
#include "dynamic-link.h"
#include <stdio-common/_itoa.h>
#include <dl-origin.h>
/* On some systems, no flag bits are given to specify file mapping. */
#ifndef MAP_FILE
@ -124,6 +126,116 @@ local_strdup (const char *s)
return (char *) memcpy (new, s, len);
}
/* Return copy of argument with all recognized dynamic string tokens
($ORIGIN and $PLATFORM for now) replaced. On some platforms it
might not be possible to determine the path from which the object
belonging to the map is loaded. In this case the path element
containing $ORIGIN is left out. */
static char *
expand_dynamic_string_token (struct link_map *l, const char *s)
{
/* We make two runs over the string. First we determine how large the
resulting string is and then we copy it over. Since this is now
frequently executed operation we are looking here not for performance
but rather for code size. */
const char *st, *sf;
size_t cnt = 0;
size_t origin_len;
size_t total;
char *result, *last_elem, *wp;
st = s;
sf = strchr (s, '$');
while (sf != NULL)
{
size_t len = 1;
if (((strncmp (&sf[1], "ORIGIN", 6) == 0 && (len = 7) != 0)
|| (strncmp (&sf[1], "PLATFORM", 8) == 0 && (len = 9) != 0))
&& (s[len] == '\0' || s[len] == '/' || s[len] == ':'))
++cnt;
st = sf + len;
sf = strchr (st, '$');
}
/* If we do not have to replace anything simply copy the string. */
if (cnt == 0)
return local_strdup (s);
/* Now we make a guess how many extra characters on top of the length
of S we need to represent the result. We know that we have CNT
replacements. Each at most can use
MAX (strlen (ORIGIN), strlen (_dl_platform))
minus 7 (which is the length of "$ORIGIN").
First get the origin string if it is not available yet. This can
only happen for the map of the executable. */
if (l->l_origin == NULL)
{
assert (l->l_name[0] == '\0');
l->l_origin = get_origin ();
origin_len = l->l_origin ? strlen (l->l_origin) : 0;
}
else
origin_len = l->l_origin == (char *) -1 ? 0 : strlen (l->l_origin);
total = strlen (s) + cnt * (MAX (origin_len, _dl_platformlen) - 7);
result = (char *) malloc (total + 1);
if (result == NULL)
return NULL;
/* Now fill the result path. While copying over the string we keep
track of the start of the last path element. When we come accross
a DST we copy over the value or (if the value is not available)
leave the entire path element out. */
last_elem = wp = result;
do
{
if (*s == '$')
{
const char *repl;
size_t len;
if (((strncmp (&s[1], "ORIGIN", 6) == 0 && (len = 7) != 0)
|| (strncmp (&s[1], "PLATFORM", 8) == 0 && (len = 9) != 0))
&& (s[len] == '\0' || s[len] == '/' || s[len] == ':'))
{
if ((repl = len == 7 ? l->l_origin : _dl_platform) != NULL
&& repl != (const char *) -1)
{
wp = __stpcpy (wp, repl);
s += len;
}
else
{
/* We cannot use this path element, the value of the
replacement is unknown. */
wp = last_elem;
s += len;
while (*s != '\0' && *s != ':')
++s;
}
}
else
/* No SDK we recognize. */
*wp++ = *s++;
}
else if (*s == ':')
{
*wp++ = *s++;
last_elem = wp;
}
else
*wp++ = *s++;
}
while (*s != '\0');
*wp = '\0';
return result;
}
/* Add `name' to the list of names for a particular shared object.
`name' is expected to have been allocated with malloc and will
be freed if the shared object already has this name.
@ -286,9 +398,10 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
static struct r_search_path_elem **
internal_function
decompose_rpath (const char *rpath, size_t additional_room, const char *where)
decompose_rpath (const char *rpath, size_t additional_room, struct link_map *l)
{
/* Make a copy we can work with. */
const char *where = l->l_name;
char *copy;
char *cp;
struct r_search_path_elem **result;
@ -318,8 +431,13 @@ decompose_rpath (const char *rpath, size_t additional_room, const char *where)
}
}
/* Make a writable copy. At the same time expand possible dynamic
string tokens. */
copy = expand_dynamic_string_token (l, rpath);
if (copy == NULL)
_dl_signal_error (ENOMEM, NULL, "cannot create RPATH copy");
/* Count the number of necessary elements in the result array. */
copy = local_strdup (rpath);
nelems = 0;
for (cp = copy; *cp != '\0'; ++cp)
if (*cp == ':')
@ -429,7 +547,7 @@ _dl_init_paths (const char *llp)
decompose_rpath ((const char *)
(l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr
+ l->l_info[DT_RPATH]->d_un.d_val),
nllp, l->l_name);
nllp, l);
}
else
{
@ -497,6 +615,9 @@ _dl_init_paths (const char *llp)
/* Map in the shared object NAME, actually located in REALNAME, and already
opened on FD. */
#ifndef EXTERNAL_MAP_FROM_FD
static
#endif
struct link_map *
_dl_map_object_from_fd (char *name, int fd, char *realname,
struct link_map *loader, int l_type)
@ -591,6 +712,12 @@ _dl_map_object_from_fd (char *name, int fd, char *realname,
LOSE ("ELF file data encoding not " byteorder_name);
if (header->e_ident[EI_VERSION] != EV_CURRENT)
LOSE ("ELF file version ident not " STRING(EV_CURRENT));
/* XXX We should be able so set system specific versions which are
allowed here. */
if (header->e_ident[EI_OSABI] != ELFOSABI_SYSV)
LOSE ("ELF file OS ABI not " STRING(ELFOSABI_SYSV));
if (header->e_ident[EI_ABIVERSION] != 0)
LOSE ("ELF file ABI version not 0");
if (header->e_version != EV_CURRENT)
LOSE ("ELF file version not " STRING(EV_CURRENT));
if (! elf_machine_matches_host (header->e_machine))
@ -1076,7 +1203,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
+ l->l_info[DT_STRTAB]->d_un.d_ptr
+ l->l_info[DT_RPATH]->d_un.d_val);
l->l_rpath_dirs =
decompose_rpath ((const char *) ptrval, 0, l->l_name);
decompose_rpath ((const char *) ptrval, 0, l);
}
if (l->l_rpath_dirs != (struct r_search_path_elem **) -1l)
@ -1127,15 +1254,17 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
}
else
{
fd = __open (name, O_RDONLY);
if (fd != -1)
/* The path may contain dynamic string tokens. */
realname = (loader
? expand_dynamic_string_token (loader, name)
: local_strdup (name));
if (realname == NULL)
fd = -1;
else
{
realname = local_strdup (name);
if (realname == NULL)
{
__close (fd);
fd = -1;
}
fd = __open (realname, O_RDONLY);
if (fd == -1)
free (realname);
}
}

View File

@ -20,6 +20,7 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <elf/ldsodefs.h>
#include <assert.h>
@ -61,5 +62,68 @@ _dl_new_object (char *realname, const char *libname, int type)
l->l_next = new;
}
/* The REALNAME is "" for the main link map. This name must be determined
specially. */
if (realname[0] == '\0')
new->l_origin = NULL;
else
{
char *origin;
if (realname[0] == '/')
{
/* It an absolute path. Use it. But we have to make a copy since
we strip out the trailing slash. */
size_t len = strlen (realname) + 1;
origin = malloc (len);
if (origin == NULL)
origin = (char *) -1;
else
memcpy (origin, realname, len);
}
else
{
size_t realname_len = strlen (realname) + 1;
size_t len = 128 + realname_len;
char *result = NULL;
/* Get the current directory name. */
origin = malloc (len);
while (origin != NULL
&& (result = __getcwd (origin, len - realname_len)) == NULL
&& errno == ERANGE)
{
len += 128;
origin = (char *) realloc (origin, len);
}
if (result == NULL)
{
/* We were not able to determine the current directory. */
if (origin != NULL)
free (origin);
origin = (char *) -1;
}
else
{
/* Now append the filename. */
char *cp = strchr (origin, '\0');
if (cp [-1] != '/')
*cp++ = '/';
memcpy (cp, realname, realname_len);
}
}
if (origin != (char *) -1)
/* Now remove the filename and the slash. Do this even if the
string is something like "/foo" which leaves an empty string. */
*strrchr (origin, '/') = '\0';
new->l_origin = origin;
}
return new;
}

View File

@ -63,6 +63,9 @@ struct link_map *_dl_profile_map;
/* This is the address of the last stack address ever used. */
void *__libc_stack_end;
/* Path where the binary is found. */
const char *_dl_origin_path;
static void non_dynamic_init (void) __attribute__ ((unused));

View File

@ -161,6 +161,9 @@ struct link_map
/* Pointer to the version information if available. */
ElfW(Half) *l_versyms;
/* String specifying the path where this object was found. */
const char *l_origin;
};
#endif /* link.h */

View File

@ -87,6 +87,7 @@ int _dl_debug_reloc;
int _dl_debug_files;
const char *_dl_inhibit_rpath; /* RPATH values which should be
ignored. */
const char *_dl_origin_path;
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
@ -1164,6 +1165,12 @@ process_envvars (enum mode *modep, int *lazyp)
_dl_hwcap_mask = strtoul (&envline[14], NULL, 0);
break;
case 11:
/* Path where the binary is found. */
if (memcmp (&envline[3], "ORIGIN_PATH", 11) == 0)
_dl_hwcap_mask = strtoul (&envline[15], NULL, 0);
break;
case 12:
/* Where to place the profiling data file. */
if (memcmp (&envline[3], "DEBUG_OUTPUT", 12) == 0)

View File

@ -82,7 +82,7 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
({ \
__typeof__ (descr->member) __value; \
if (sizeof (__value) == 1) \
__asm__ __volatile__ ("movb %%gs:%c1,%b0" \
__asm__ __volatile__ ("movb %%gs:%P1,%b0" \
: "=r" (__value) \
: "0" (0), \
"i" (offsetof (struct _pthread_descr_struct, \
@ -93,7 +93,7 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
/* There should not be any value with a size other than 1 or 4. */ \
abort (); \
\
__asm__ __volatile__ ("movl %%gs:%c1,%0" \
__asm__ __volatile__ ("movl %%gs:%P1,%0" \
: "=r" (__value) \
: "i" (offsetof (struct _pthread_descr_struct, \
member))); \
@ -106,7 +106,7 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
({ \
__typeof__ (descr->member) __value = (value); \
if (sizeof (__value) == 1) \
__asm__ __volatile__ ("movb %0,%%gs:%c1" : \
__asm__ __volatile__ ("movb %0,%%gs:%P1" : \
: "r" (__value), \
"i" (offsetof (struct _pthread_descr_struct, \
member))); \
@ -116,7 +116,7 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
/* There should not be any value with a size other than 1 or 4. */ \
abort (); \
\
__asm__ __volatile__ ("movl %0,%%gs:%c1" : \
__asm__ __volatile__ ("movl %0,%%gs:%P1" : \
: "r" (__value), \
"i" (offsetof (struct _pthread_descr_struct, \
member))); \

View File

@ -0,0 +1,47 @@
/* Find path of executable.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Generally it is not possible to implement this. We have to fall
back on a solution where the user provides the information. */
extern const char *_dl_origin_path;
static inline const char *
get_origin (void)
{
char *result = (char *) -1;
/* We use te environment variable LD_ORIGIN_PATH. If it is set make
a copy and strip out trailing slashes. */
if (_dl_origin_path != NULL)
{
size_t len = strlen (_dl_origin_path);
result = malloc (len + 1);
if (result == NULL)
result = (char *) -1;
else
{
char *cp = __mempcpy (result, _dl_origin_path, len);
while (cp > result && cp[-1] == '/')
--cp;
*cp = '\0';
}
}
return result;
}

View File

@ -124,6 +124,8 @@ $(inst_libdir)/libc.so: $(rpcuserlibs)
# objects directly into the shared object.
ifeq (elf,$(subdir))
$(objpfx)librtld.os: $(rpcuserlibs:.so=_pic.a)
CFLAGS-dl-load.c = -DEXTERNAL_MAP_FROM_FD
endif
# We need these libs to link static programs in the libc source tree, too.

View File

@ -0,0 +1,67 @@
/* Find path of executable.
Copyright (C) 1998 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* On Linux >= 2.1 systems which have the dcache implementation we can get
the path of the application from the /proc/self/exe symlink. Try this
first and fall back on the generic method if necessary. */
extern const char *_dl_origin_path;
static inline const char *
get_origin (void)
{
char linkval[PATH_MAX];
char *result;
if (readlink ("/proc/self/exe", linkval, PATH_MAX) != -1
&& result[0] != '[')
{
/* We can use this value. */
char *last_slash = strrchr (linkval, '/');
result = (char *) malloc (linkval - last_slash + 1);
if (result == NULL)
result = (char *) -1;
else
*((char *) __mempcpy (result, linkval, linkval - last_slash)) = '\0';
}
else
{
size_t len = 0;
result = (char *) -1;
/* We use te environment variable LD_ORIGIN_PATH. If it is set make
a copy and strip out trailing slashes. */
if (_dl_origin_path != NULL)
{
size_t len = strlen (_dl_origin_path);
result = malloc (len + 1);
if (result == NULL)
result = (char *) -1;
else
{
char *cp = __mempcpy (result, _dl_origin_path, len);
while (cp > result && cp[-1] == '/')
--cp;
*cp = '\0';
}
}
}
return result;
}