aboutsummaryrefslogtreecommitdiff
path: root/elf/dl-libc.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2018-01-04 18:46:17 +0100
committerFlorian Weimer <fweimer@redhat.com>2018-01-04 18:46:24 +0100
commit82eef55f8fad3e00c53050de5d6ebea08df488b3 (patch)
treee0e1ed86b2296703182789d7f5ea607bf066ffe4 /elf/dl-libc.c
parent7abf02f3ee7627d617def77d0d6e7bea2da8d98c (diff)
downloadglibc-82eef55f8fad3e00c53050de5d6ebea08df488b3.zip
glibc-82eef55f8fad3e00c53050de5d6ebea08df488b3.tar.gz
glibc-82eef55f8fad3e00c53050de5d6ebea08df488b3.tar.bz2
elf: Support dlvsym within libc.so
This commit adds a new _dl_open_hook entry for dlvsym and implements the function using the existing dl_lookup_symbol_x function supplied by the dynamic loader. A new hook variable, _dl_open_hook2, is introduced, which should make this change suitable for backporting: For old statically linked binaries, __libc_dlvsym will always return NULL.
Diffstat (limited to 'elf/dl-libc.c')
-rw-r--r--elf/dl-libc.c73
1 files changed, 72 insertions, 1 deletions
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index c6818e0..fc01f55 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -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;
@@ -78,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)
{
@@ -99,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);
@@ -112,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
@@ -119,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)
@@ -142,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
@@ -192,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
@@ -211,6 +249,39 @@ __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)
{