summaryrefslogtreecommitdiff
path: root/elf/dl-libc.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-libc.c')
-rw-r--r--elf/dl-libc.c86
1 files changed, 78 insertions, 8 deletions
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index d56de1a57a..fc01f5514d 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -1,5 +1,5 @@
/* Handle loading and unloading shared objects for internal libc purposes.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
@@ -20,6 +20,7 @@
#include <dlfcn.h>
#include <stdlib.h>
#include <ldsodefs.h>
+#include <dl-hash.h>
extern int __libc_argc attribute_hidden;
extern char **__libc_argv attribute_hidden;
@@ -36,15 +37,14 @@ extern char **__environ;
Much of this code came from gconv_dl.c with slight modifications. */
static int
-internal_function
dlerror_run (void (*operate) (void *), void *args)
{
const char *objname;
const char *last_errstring = NULL;
bool malloced;
- int result = (GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
- operate, args)
+ int result = (_dl_catch_error (&objname, &last_errstring, &malloced,
+ operate, args)
?: last_errstring != NULL);
if (result && malloced)
@@ -79,6 +79,15 @@ struct do_dlsym_args
const ElfW(Sym) *ref;
};
+struct do_dlvsym_args
+{
+ /* dlvsym is like dlsym. */
+ struct do_dlsym_args dlsym;
+
+ /* But dlvsym needs a version as well. */
+ struct r_found_version version;
+};
+
static void
do_dlopen (void *ptr)
{
@@ -100,6 +109,18 @@ do_dlsym (void *ptr)
}
static void
+do_dlvsym (void *ptr)
+{
+ struct do_dlvsym_args *args = ptr;
+ args->dlsym.ref = NULL;
+ args->dlsym.loadbase
+ = GLRO(dl_lookup_symbol_x) (args->dlsym.name, args->dlsym.map,
+ &args->dlsym.ref,
+ args->dlsym.map->l_local_scope,
+ &args->version, 0, 0, NULL);
+}
+
+static void
do_dlclose (void *ptr)
{
GLRO(dl_close) ((struct link_map *) ptr);
@@ -113,6 +134,7 @@ struct dl_open_hook
void *(*dlopen_mode) (const char *name, int mode);
void *(*dlsym) (void *map, const char *name);
int (*dlclose) (void *map);
+ void *(*dlvsym) (void *map, const char *name, const char *version);
};
#ifdef SHARED
@@ -120,6 +142,15 @@ extern struct dl_open_hook *_dl_open_hook;
libc_hidden_proto (_dl_open_hook);
struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
libc_hidden_data_def (_dl_open_hook);
+
+/* The dlvsym member was added retroactively to struct dl_open_hook.
+ Static applications which have it will set _dl_open_hook2 in
+ addition to _dl_open_hook. */
+extern struct dl_open_hook *_dl_open_hook2;
+libc_hidden_proto (_dl_open_hook2);
+struct dl_open_hook *_dl_open_hook2 __attribute__ ((nocommon));
+libc_hidden_data_def (_dl_open_hook2);
+
#else
static void
do_dlsym_private (void *ptr)
@@ -143,7 +174,8 @@ static struct dl_open_hook _dl_open_hook =
{
.dlopen_mode = __libc_dlopen_mode,
.dlsym = __libc_dlsym,
- .dlclose = __libc_dlclose
+ .dlclose = __libc_dlclose,
+ .dlvsym = __libc_dlvsym,
};
#endif
@@ -158,7 +190,7 @@ __libc_dlopen_mode (const char *name, int mode)
args.caller_dlopen = RETURN_ADDRESS (0);
#ifdef SHARED
- if (__glibc_unlikely (_dl_open_hook != NULL))
+ if (!rtld_active ())
return _dl_open_hook->dlopen_mode (name, mode);
return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
#else
@@ -193,6 +225,11 @@ __libc_register_dl_open_hook (struct link_map *map)
hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
if (hook != NULL)
*hook = &_dl_open_hook;
+
+ /* For dlvsym support. */
+ hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook2");
+ if (hook != NULL)
+ *hook = &_dl_open_hook;
}
#endif
@@ -204,7 +241,7 @@ __libc_dlsym (void *map, const char *name)
args.name = name;
#ifdef SHARED
- if (__glibc_unlikely (_dl_open_hook != NULL))
+ if (!rtld_active ())
return _dl_open_hook->dlsym (map, name);
#endif
return (dlerror_run (do_dlsym, &args) ? NULL
@@ -212,11 +249,44 @@ __libc_dlsym (void *map, const char *name)
}
libc_hidden_def (__libc_dlsym)
+/* Replacement for dlvsym. MAP must be a real map. This function
+ returns NULL without setting the dlerror value in case of static
+ dlopen from an old binary. */
+void *
+__libc_dlvsym (void *map, const char *name, const char *version)
+{
+#ifdef SHARED
+ if (!rtld_active ())
+ {
+ /* The static application is too old and does not provide the
+ dlvsym hook. */
+ if (_dl_open_hook2 == NULL)
+ return NULL;
+ return _dl_open_hook2->dlvsym (map, name, version);
+ }
+#endif
+
+ struct do_dlvsym_args args;
+ args.dlsym.map = map;
+ args.dlsym.name = name;
+
+ /* See _dl_vsym in dl-sym.c. */
+ args.version.name = version;
+ args.version.hidden = 1;
+ args.version.hash = _dl_elf_hash (version);
+ args.version.filename = NULL;
+
+ return (dlerror_run (do_dlvsym, &args) ? NULL
+ : (void *) (DL_SYMBOL_ADDRESS (args.dlsym.loadbase,
+ args.dlsym.ref)));
+}
+libc_hidden_def (__libc_dlvsym)
+
int
__libc_dlclose (void *map)
{
#ifdef SHARED
- if (__glibc_unlikely (_dl_open_hook != NULL))
+ if (!rtld_active ())
return _dl_open_hook->dlclose (map);
#endif
return dlerror_run (do_dlclose, map);