Correct the lookup order of _rtld_symlook_default and make

_rtld_find_symdef use _rtld_symlook_default.

This reduces the code size and means that dlsym(RTLD_DEFAULT,...) has the
correct lookup order.

Reviewed by kleink. Thanks.
This commit is contained in:
skrll 2005-10-13 11:14:09 +00:00
parent 34cace8bd1
commit bd7cbb198e
1 changed files with 44 additions and 86 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: symbol.c,v 1.39 2005/05/10 13:15:56 chs Exp $ */ /* $NetBSD: symbol.c,v 1.40 2005/10/13 11:14:09 skrll Exp $ */
/* /*
* Copyright 1996 John D. Polstra. * Copyright 1996 John D. Polstra.
@ -40,7 +40,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
__RCSID("$NetBSD: symbol.c,v 1.39 2005/05/10 13:15:56 chs Exp $"); __RCSID("$NetBSD: symbol.c,v 1.40 2005/10/13 11:14:09 skrll Exp $");
#endif /* not lint */ #endif /* not lint */
#include <err.h> #include <err.h>
@ -196,77 +196,31 @@ _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
{ {
const Elf_Sym *ref; const Elf_Sym *ref;
const Elf_Sym *def; const Elf_Sym *def;
const Elf_Sym *symp;
const Obj_Entry *obj;
const Obj_Entry *defobj; const Obj_Entry *defobj;
const Objlist_Entry *elm;
const char *name; const char *name;
unsigned long hash; unsigned long hash;
ref = refobj->symtab + symnum; ref = refobj->symtab + symnum;
name = refobj->strtab + ref->st_name; name = refobj->strtab + ref->st_name;
hash = _rtld_elf_hash(name);
def = NULL;
defobj = NULL;
/* Look first in the referencing object if linked symbolically */
if (refobj->symbolic) {
symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
if (symp != NULL) {
def = symp;
defobj = refobj;
}
}
/* Search all objects loaded at program start up. */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("search _rtld_list_main"));
symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/* Search all RTLD_GLOBAL objects. */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("search _rtld_list_global"));
symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/* Search all dlopened DAGs containing the referencing object. */
SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
rdbg(("search DAG with root %p (%s)", elm->obj, elm->obj->path));
symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/* /*
* Search the dynamic linker itself, and possibly resolve the * We don't have to do a full scale lookup if the symbol is local.
* symbol from there. This is how the application links to * We know it will bind to the instance in this load module; to
* dynamic linker services such as dlopen. Only the values listed * which we already have a pointer (ie ref).
* in the "_rtld_exports" array can be resolved from the dynamic linker.
*/ */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { if (ELF_ST_BIND(ref->st_info) != STB_LOCAL) {
rdbg(("search rtld itself")); if (ELF_ST_TYPE(ref->st_info) == STT_SECTION) {
symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt); _rtld_error("%s: Bogus symbol table entry %lu",
if (symp != NULL && _rtld_is_exported(symp)) { refobj->path, symnum);
def = symp; }
defobj = &_rtld_objself;
} hash = _rtld_elf_hash(name);
defobj = NULL;
def = _rtld_symlook_default(name, hash, refobj, &defobj, in_plt);
} else {
rdbg(("STB_LOCAL symbol %s in %s", name, refobj->path));
def = ref;
defobj = refobj;
} }
/* /*
@ -309,6 +263,7 @@ _rtld_symlook_default(const char *name, unsigned long hash,
/* Look first in the referencing object if linked symbolically. */ /* Look first in the referencing object if linked symbolically. */
if (refobj->symbolic) { if (refobj->symbolic) {
rdbg(("search referencing object"));
symp = _rtld_symlook_obj(name, hash, refobj, in_plt); symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
if (symp != NULL) { if (symp != NULL) {
def = symp; def = symp;
@ -318,9 +273,23 @@ _rtld_symlook_default(const char *name, unsigned long hash,
/* Search all objects loaded at program start up. */ /* Search all objects loaded at program start up. */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt); rdbg(("search _rtld_list_main"));
symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj,
in_plt);
if (symp != NULL && if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
/* Search all RTLD_GLOBAL objects. */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("search _rtld_list_global"));
symp = _rtld_symlook_list(name, hash, &_rtld_list_global,
&obj, in_plt);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp; def = symp;
defobj = obj; defobj = obj;
} }
@ -330,8 +299,10 @@ _rtld_symlook_default(const char *name, unsigned long hash,
SIMPLEQ_FOREACH(elm, &refobj->dldags, link) { SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
break; break;
symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, rdbg(("search DAG with root %p (%s)", elm->obj,
in_plt); elm->obj->path));
symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers,
&obj, in_plt);
if (symp != NULL && if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp; def = symp;
@ -339,34 +310,21 @@ _rtld_symlook_default(const char *name, unsigned long hash,
} }
} }
/* Search all DAGs whose roots are RTLD_GLOBAL objects. */
SIMPLEQ_FOREACH(elm, &_rtld_list_global, link) {
if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
in_plt);
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
}
}
#ifdef notyet
/* /*
* Search the dynamic linker itself, and possibly resolve the * Search the dynamic linker itself, and possibly resolve the
* symbol from there. This is how the application links to * symbol from there. This is how the application links to
* dynamic linker services such as dlopen. Only the values listed * dynamic linker services such as dlopen. Only the values listed
* in the "exports" array can be resolved from the dynamic linker. * in the "_rtld_exports" array can be resolved from the dynamic
* linker.
*/ */
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
rdbg(("Search the dynamic linker itself."));
symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt); symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
if (symp != NULL && is_exported(symp)) { if (symp != NULL && _rtld_is_exported(symp)) {
def = symp; def = symp;
defobj = &_rtld_objself; defobj = &_rtld_objself;
} }
} }
#endif
if (def != NULL) if (def != NULL)
*defobj_out = defobj; *defobj_out = defobj;