diff options
author | kan <kan@FreeBSD.org> | 2008-10-10 00:16:32 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2008-10-10 00:16:32 +0000 |
commit | d53cb6ffcf6fddc63c399fb2ea4620e682597b38 (patch) | |
tree | 96fb448f8fe2d62582809928c6e81ebd28b02202 /libexec | |
parent | b4da579f7f8907132cf9121a6ed3f46e54c2d528 (diff) | |
download | FreeBSD-src-d53cb6ffcf6fddc63c399fb2ea4620e682597b38.zip FreeBSD-src-d53cb6ffcf6fddc63c399fb2ea4620e682597b38.tar.gz |
Allow strong symbols to override weak ones for lookups done through
dlsym with RTLD_NEXT/RTLD_SELF handles.
Allow symbols from ld-elf.so to be located this way too.
Based on report and original patch from sobomax@.
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-elf/rtld.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 7e0f8b1..144ea6c 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -1925,7 +1925,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, { DoneList donelist; const Obj_Entry *obj, *defobj; - const Elf_Sym *def; + const Elf_Sym *def, *symp; unsigned long hash; int lockstate; @@ -1951,9 +1951,26 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, if (handle == RTLD_NEXT) obj = obj->next; for (; obj != NULL; obj = obj->next) { - if ((def = symlook_obj(name, hash, obj, ve, flags)) != NULL) { - defobj = obj; - break; + if ((symp = symlook_obj(name, hash, obj, ve, flags)) != NULL) { + if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { + def = symp; + defobj = obj; + if (ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + } + } + } + /* + * Search the dynamic linker itself, and possibly resolve the + * symbol from there. This is how the application links to + * dynamic linker services such as dlopen. Only the values listed + * in the "exports" array can be resolved from the dynamic linker. + */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_obj(name, hash, &obj_rtld, ve, flags); + if (symp != NULL && is_exported(symp)) { + def = symp; + defobj = &obj_rtld; } } } else { |