aboutsummaryrefslogtreecommitdiff
path: root/REORG.TODO/elf/dl-sym.c
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/elf/dl-sym.c')
-rw-r--r--REORG.TODO/elf/dl-sym.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/REORG.TODO/elf/dl-sym.c b/REORG.TODO/elf/dl-sym.c
new file mode 100644
index 0000000000..7cd6e97643
--- /dev/null
+++ b/REORG.TODO/elf/dl-sym.c
@@ -0,0 +1,274 @@
+/* Look up a symbol in a shared object loaded by `dlopen'.
+ Copyright (C) 1999-2017 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#include <dlfcn.h>
+#include <ldsodefs.h>
+#include <dl-hash.h>
+#include <sysdep-cancel.h>
+#include <dl-tls.h>
+#include <dl-irel.h>
+
+
+#ifdef SHARED
+/* Systems which do not have tls_index also probably have to define
+ DONT_USE_TLS_INDEX. */
+
+# ifndef __TLS_GET_ADDR
+# define __TLS_GET_ADDR __tls_get_addr
+# endif
+
+/* Return the symbol address given the map of the module it is in and
+ the symbol record. This is used in dl-sym.c. */
+static void *
+internal_function
+_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
+{
+# ifndef DONT_USE_TLS_INDEX
+ tls_index tmp =
+ {
+ .ti_module = map->l_tls_modid,
+ .ti_offset = ref->st_value
+ };
+
+ return __TLS_GET_ADDR (&tmp);
+# else
+ return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
+# endif
+}
+#endif
+
+
+struct call_dl_lookup_args
+{
+ /* Arguments to do_dlsym. */
+ struct link_map *map;
+ const char *name;
+ struct r_found_version *vers;
+ int flags;
+
+ /* Return values of do_dlsym. */
+ lookup_t loadbase;
+ const ElfW(Sym) **refp;
+};
+
+static void
+call_dl_lookup (void *ptr)
+{
+ struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
+ args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
+ args->map->l_scope, args->vers, 0,
+ args->flags, NULL);
+}
+
+
+static void *
+internal_function
+do_sym (void *handle, const char *name, void *who,
+ struct r_found_version *vers, int flags)
+{
+ const ElfW(Sym) *ref = NULL;
+ lookup_t result;
+ ElfW(Addr) caller = (ElfW(Addr)) who;
+
+ struct link_map *l = _dl_find_dso_for_object (caller);
+ /* If the address is not recognized the call comes from the main
+ program (we hope). */
+ struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+ if (handle == RTLD_DEFAULT)
+ {
+ /* Search the global scope. We have the simple case where
+ we look up in the scope of an object which was part of
+ the initial binary. And then the more complex part
+ where the object is dynamically loaded and the scope
+ array can change. */
+ if (RTLD_SINGLE_THREAD_P)
+ result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
+ match->l_scope, vers, 0,
+ flags | DL_LOOKUP_ADD_DEPENDENCY,
+ NULL);
+ else
+ {
+ struct call_dl_lookup_args args;
+ args.name = name;
+ args.map = match;
+ args.vers = vers;
+ args.flags
+ = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
+ args.refp = &ref;
+
+ THREAD_GSCOPE_SET_FLAG ();
+
+ const char *objname;
+ const char *errstring = NULL;
+ bool malloced;
+ int err = _dl_catch_error (&objname, &errstring, &malloced,
+ call_dl_lookup, &args);
+
+ THREAD_GSCOPE_RESET_FLAG ();
+
+ if (__glibc_unlikely (errstring != NULL))
+ {
+ /* The lookup was unsuccessful. Rethrow the error. */
+ char *errstring_dup = strdupa (errstring);
+ char *objname_dup = strdupa (objname);
+ if (malloced)
+ free ((char *) errstring);
+
+ _dl_signal_error (err, objname_dup, NULL, errstring_dup);
+ /* NOTREACHED */
+ }
+
+ result = args.map;
+ }
+ }
+ else if (handle == RTLD_NEXT)
+ {
+ if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
+ {
+ if (match == NULL
+ || caller < match->l_map_start
+ || caller >= match->l_map_end)
+ _dl_signal_error (0, NULL, NULL, N_("\
+RTLD_NEXT used in code not dynamically loaded"));
+ }
+
+ struct link_map *l = match;
+ while (l->l_loader != NULL)
+ l = l->l_loader;
+
+ result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
+ vers, 0, 0, match);
+ }
+ else
+ {
+ /* Search the scope of the given object. */
+ struct link_map *map = handle;
+ result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
+ vers, 0, flags, NULL);
+ }
+
+ if (ref != NULL)
+ {
+ void *value;
+
+#ifdef SHARED
+ if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
+ /* The found symbol is a thread-local storage variable.
+ Return the address for to the current thread. */
+ value = _dl_tls_symaddr (result, ref);
+ else
+#endif
+ value = DL_SYMBOL_ADDRESS (result, ref);
+
+ /* Resolve indirect function address. */
+ if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
+ {
+ DL_FIXUP_VALUE_TYPE fixup
+ = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
+ fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
+ value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
+ }
+
+#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 (__glibc_unlikely (GLRO(dl_naudit) > 0))
+ {
+ const char *strtab = (const char *) D_PTR (result,
+ l_info[DT_STRTAB]);
+ /* Compute index of the symbol entry in the symbol table of
+ the DSO with the definition. */
+ unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
+ l_info[DT_SYMTAB]));
+
+ if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
+ {
+ unsigned int altvalue = 0;
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ /* Synthesize a symbol record where the st_value field is
+ the result. */
+ ElfW(Sym) sym = *ref;
+ sym.st_value = (ElfW(Addr)) value;
+
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->symbind != NULL
+ && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
+ != 0
+ || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
+ != 0)))
+ {
+ unsigned int flags = altvalue | LA_SYMB_DLSYM;
+ uintptr_t new_value
+ = afct->symbind (&sym, ndx,
+ &match->l_audit[cnt].cookie,
+ &result->l_audit[cnt].cookie,
+ &flags, strtab + ref->st_name);
+ if (new_value != (uintptr_t) sym.st_value)
+ {
+ altvalue = LA_SYMB_ALTVALUE;
+ sym.st_value = new_value;
+ }
+ }
+
+ afct = afct->next;
+ }
+
+ value = (void *) sym.st_value;
+ }
+ }
+#endif
+
+ return value;
+ }
+
+ return NULL;
+}
+
+
+void *
+internal_function
+_dl_vsym (void *handle, const char *name, const char *version, void *who)
+{
+ struct r_found_version vers;
+
+ /* Compute hash value to the version string. */
+ vers.name = version;
+ vers.hidden = 1;
+ vers.hash = _dl_elf_hash (version);
+ /* We don't have a specific file where the symbol can be found. */
+ vers.filename = NULL;
+
+ return do_sym (handle, name, who, &vers, 0);
+}
+
+
+void *
+internal_function
+_dl_sym (void *handle, const char *name, void *who)
+{
+ return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
+}