Attempt to give dlsym() the same symbol-searching semantics as _rtld_bind().

Tested in a handful of cases.
Reviewed by: a dead silence
This commit is contained in:
mycroft 2003-04-23 17:40:25 +00:00
parent 5ca6f100a3
commit 8826c5e475
3 changed files with 53 additions and 78 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtld.c,v 1.90 2002/12/14 15:37:57 junyoung Exp $ */
/* $NetBSD: rtld.c,v 1.91 2003/04/23 17:40:25 mycroft Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -367,8 +367,6 @@ _rtld(sp, relocbase)
_rtld_objmain->pathlen = strlen(_rtld_objmain->path);
}
_rtld_objmain->mainprog = true;
/*
* Get the actual dynamic linker pathname from the executable if
* possible. (It should always be possible.) That ensures that
@ -673,19 +671,10 @@ _rtld_dlsym(handle, name)
const char *name;
{
const Obj_Entry *obj;
unsigned long hash;
const Elf_Sym *def;
const Obj_Entry *defobj;
hash = _rtld_elf_hash(name);
def = NULL;
defobj = NULL;
if (handle == NULL
#if 0
|| handle == RTLD_NEXT
#endif
) {
if (handle == NULL) {
void *retaddr;
retaddr = __builtin_return_address(0); /* __GNUC__ only */
@ -693,33 +682,14 @@ _rtld_dlsym(handle, name)
_rtld_error("Cannot determine caller's shared object");
return NULL;
}
if (handle == NULL) { /* Just the caller's shared object. */
def = _rtld_symlook_obj(name, hash, obj, false);
defobj = obj;
} else { /* All the shared objects after the caller's */
while ((obj = obj->next) != NULL) {
if ((def = _rtld_symlook_obj(name, hash, obj, false)) != NULL) {
defobj = obj;
break;
}
}
}
} else {
if ((obj = _rtld_dlcheck(handle)) == NULL)
if ((obj = _rtld_dlcheck(handle)) == NULL) {
_rtld_error("Handle not found");
return NULL;
if (obj->mainprog) {
/* Search main program and all libraries loaded by it. */
def = _rtld_symlook_list(name, hash, &_rtld_list_main, &defobj, false);
} else {
/*
* XXX - This isn't correct. The search should include the whole
* DAG rooted at the given object.
*/
def = _rtld_symlook_obj(name, hash, obj, false);
defobj = obj;
}
}
def = _rtld_find_symname(name, obj, &defobj, false);
if (def != NULL) {
#ifdef __HAVE_FUNCTION_DESCRIPTORS
@ -728,10 +698,10 @@ _rtld_dlsym(handle, name)
def, 0);
#endif /* __HAVE_FUNCTION_DESCRIPTORS */
return defobj->relocbase + def->st_value;
} else {
_rtld_error("Undefined symbol \"%s\"", name);
return NULL;
}
_rtld_error("Undefined symbol \"%s\"", name);
return NULL;
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtld.h,v 1.65 2002/12/05 04:56:57 junyoung Exp $ */
/* $NetBSD: rtld.h,v 1.66 2003/04/23 17:40:25 mycroft Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -176,8 +176,7 @@ typedef struct Struct_Obj_Entry {
int (*dlclose) __P((void *));
int (*dladdr) __P((const void *, Dl_info *));
u_int32_t mainprog:1, /* True if this is the main program */
rtld:1, /* True if this is the dynamic linker */
u_int32_t rtld:1, /* True if this is the dynamic linker */
textrel:1, /* True if there are relocations to
* text seg */
symbolic:1, /* True if generated with
@ -256,6 +255,8 @@ Obj_Entry *_rtld_load_library __P((const char *, const Obj_Entry *, int));
unsigned long _rtld_elf_hash __P((const char *));
const Elf_Sym *_rtld_symlook_obj __P((const char *, unsigned long,
const Obj_Entry *, bool));
const Elf_Sym *_rtld_find_symname __P((const char *, const Obj_Entry *,
const Obj_Entry **, bool));
const Elf_Sym *_rtld_find_symdef __P((unsigned long, const Obj_Entry *,
const Obj_Entry **, bool));
const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,

View File

@ -1,4 +1,4 @@
/* $NetBSD: symbol.c,v 1.25 2002/10/05 11:59:04 mycroft Exp $ */
/* $NetBSD: symbol.c,v 1.26 2003/04/23 17:40:25 mycroft Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -83,11 +83,9 @@ _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
{
const Elf_Sym *symp;
const Elf_Sym *def;
const Obj_Entry *defobj;
const Objlist_Entry *elm;
def = NULL;
defobj = NULL;
SIMPLEQ_FOREACH(elm, objlist, link) {
rdbg(("search object %p (%s)", elm->obj, elm->obj->path));
if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
@ -95,14 +93,12 @@ _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
if ((def == NULL) ||
(ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = elm->obj;
*defobj_out = elm->obj;
if (ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
}
}
}
if (def != NULL)
*defobj_out = defobj;
return def;
}
@ -166,33 +162,26 @@ _rtld_symlook_obj(name, hash, obj, in_plt)
* defining object via the reference parameter DEFOBJ_OUT.
*/
const Elf_Sym *
_rtld_find_symdef(symnum, refobj, defobj_out, in_plt)
unsigned long symnum;
_rtld_find_symname(name, refobj, defobj_out, in_plt)
const char *name;
const Obj_Entry *refobj;
const Obj_Entry **defobj_out;
bool in_plt;
{
const Elf_Sym *ref;
const Elf_Sym *def;
const Elf_Sym *symp;
const Obj_Entry *obj;
const Obj_Entry *defobj;
const Objlist_Entry *elm;
const char *name;
unsigned long hash;
ref = refobj->symtab + symnum;
name = refobj->strtab + ref->st_name;
hash = _rtld_elf_hash(name);
def = NULL;
defobj = NULL;
if (refobj->symbolic) { /* Look first in the referencing object */
symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
if (symp != NULL) {
def = symp;
defobj = refobj;
*defobj_out = refobj;
}
}
@ -203,7 +192,7 @@ _rtld_find_symdef(symnum, refobj, defobj_out, in_plt)
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
*defobj_out = obj;
}
}
@ -216,7 +205,7 @@ _rtld_find_symdef(symnum, refobj, defobj_out, in_plt)
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
*defobj_out = obj;
}
}
@ -227,26 +216,41 @@ _rtld_find_symdef(symnum, refobj, defobj_out, in_plt)
if (symp != NULL &&
(def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
def = symp;
defobj = obj;
*defobj_out = obj;
}
}
/*
* If we found no definition and the reference is weak, treat the
* symbol as having the value zero.
*/
if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
rdbg((" returning _rtld_sym_zero@_rtld_objmain"));
def = &_rtld_sym_zero;
defobj = _rtld_objmain;
}
if (def != NULL)
*defobj_out = defobj;
else {
rdbg(("lookup failed"));
_rtld_error("%s: Undefined %ssymbol \"%s\" (symnum = %ld)",
refobj->path, in_plt ? "PLT " : "", name, symnum);
}
return def;
}
const Elf_Sym *
_rtld_find_symdef(symnum, refobj, defobj_out, in_plt)
unsigned long symnum;
const Obj_Entry *refobj;
const Obj_Entry **defobj_out;
bool in_plt;
{
const Elf_Sym *ref, *def;
const char *name;
ref = refobj->symtab + symnum;
name = refobj->strtab + ref->st_name;
def = _rtld_find_symname(name, refobj, defobj_out, in_plt);
if (def == NULL) {
if (ELF_ST_BIND(ref->st_info) == STB_WEAK) {
/*
* If we found no definition and the reference is weak,
* treat the symbol as having the value zero.
*/
rdbg((" returning _rtld_sym_zero@_rtld_objmain"));
def = &_rtld_sym_zero;
*defobj_out = _rtld_objmain;
} else {
rdbg(("lookup failed"));
_rtld_error("%s: Undefined %ssymbol \"%s\" (symnum = %ld)",
refobj->path, in_plt ? "PLT " : "", name, symnum);
}
}
return (def);
}