Module Name: src Committed By: kamil Date: Sat Feb 29 04:21:42 UTC 2020
Modified Files: src/libexec/ld.elf_so: symbol.c Log Message: Separate matched symbol functionality out of _rtld_symlook_obj() Simplifies the code and it will allow to use the matched symbol functionality by other users. To generate a diff of this commit: cvs rdiff -u -r1.69 -r1.70 src/libexec/ld.elf_so/symbol.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/libexec/ld.elf_so/symbol.c diff -u src/libexec/ld.elf_so/symbol.c:1.69 src/libexec/ld.elf_so/symbol.c:1.70 --- src/libexec/ld.elf_so/symbol.c:1.69 Wed Aug 9 18:44:32 2017 +++ src/libexec/ld.elf_so/symbol.c Sat Feb 29 04:21:42 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: symbol.c,v 1.69 2017/08/09 18:44:32 joerg Exp $ */ +/* $NetBSD: symbol.c,v 1.70 2020/02/29 04:21:42 kamil Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -40,7 +40,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: symbol.c,v 1.69 2017/08/09 18:44:32 joerg Exp $"); +__RCSID("$NetBSD: symbol.c,v 1.70 2020/02/29 04:21:42 kamil Exp $"); #endif /* not lint */ #include <err.h> @@ -193,6 +193,119 @@ _rtld_symlook_needed(const char *name, u return def; } +static bool +_rtld_symlook_obj_matched_symbol(const char *name, + const Obj_Entry *obj, u_int flags, const Ver_Entry *ventry, + unsigned long symnum, const Elf_Sym **vsymp, int *vcount) +{ + const Elf_Sym *symp; + const char *strp; + Elf_Half verndx; + + symp = obj->symtab + symnum; + strp = obj->strtab + symp->st_name; + rdbg(("check \"%s\" vs \"%s\" in %s", name, strp, obj->path)); + if (name[1] != strp[1] || strcmp(name, strp)) + return false; +#if defined(__mips__) || defined(__vax__) + if (symp->st_shndx == SHN_UNDEF) + continue; +#else + /* + * XXX DANGER WILL ROBINSON! + * If we have a function pointer in the executable's + * data section, it points to the executable's PLT + * slot, and there is NO relocation emitted. To make + * the function pointer comparable to function pointers + * in shared libraries, we must resolve data references + * in the libraries to point to PLT slots in the + * executable, if they exist. + */ + if (symp->st_shndx == SHN_UNDEF && + ((flags & SYMLOOK_IN_PLT) || + symp->st_value == 0 || + ELF_ST_TYPE(symp->st_info) != STT_FUNC)) + return false; +#endif + + if (ventry == NULL) { + if (obj->versyms != NULL) { + verndx = VER_NDX(obj->versyms[symnum].vs_vers); + if (verndx > obj->vertabnum) { + _rtld_error("%s: symbol %s references " + "wrong version %d", obj->path, + &obj->strtab[symnum], verndx); + return false; + } + + /* + * If we are not called from dlsym (i.e. this + * is a normal relocation from unversioned + * binary), accept the symbol immediately + * if it happens to have first version after + * this shared object became versioned. + * Otherwise, if symbol is versioned and not + * hidden, remember it. If it is the only + * symbol with this name exported by the shared + * object, it will be returned as a match at the + * end of the function. If symbol is global + * (verndx < 2) accept it unconditionally. + */ + if (!(flags & SYMLOOK_DLSYM) && + verndx == VER_NDX_GIVEN) { + *vsymp = symp; + return true; + } else if (verndx >= VER_NDX_GIVEN) { + if (!(obj->versyms[symnum].vs_vers & VER_NDX_HIDDEN)) { + if (*vsymp == NULL) + *vsymp = symp; + (*vcount)++; + } + return false; + } + } + *vsymp = symp; + return true; + } else { + if (obj->versyms == NULL) { + if (_rtld_object_match_name(obj, ventry->name)){ + _rtld_error("%s: object %s should " + "provide version %s for symbol %s", + _rtld_objself.path, obj->path, + ventry->name, &obj->strtab[symnum]); + return false; + } + } else { + verndx = VER_NDX(obj->versyms[symnum].vs_vers); + if (verndx > obj->vertabnum) { + _rtld_error("%s: symbol %s references " + "wrong version %d", obj->path, + &obj->strtab[symnum], verndx); + return false; + } + if (obj->vertab[verndx].hash != ventry->hash || + strcmp(obj->vertab[verndx].name, ventry->name)) { + /* + * Version does not match. Look if this + * is a global symbol and if it is not + * hidden. If global symbol (verndx < 2) + * is available, use it. Do not return + * symbol if we are called by dlvsym, + * because dlvsym looks for a specific + * version and default one is not what + * dlvsym wants. + */ + if ((flags & SYMLOOK_DLSYM) || + (obj->versyms[symnum].vs_vers & VER_NDX_HIDDEN) || + (verndx >= VER_NDX_GIVEN)) + return false; + } + } + *vsymp = symp; + return true; + } +} + /* * Search the symbol table of a single shared object for a symbol of * the given name. Returns a pointer to the symbol, or NULL if no @@ -207,115 +320,17 @@ _rtld_symlook_obj(const char *name, unsi { unsigned long symnum; const Elf_Sym *vsymp = NULL; - Elf_Half verndx; int vcount = 0; for (symnum = obj->buckets[fast_remainder32(hash, obj->nbuckets, obj->nbuckets_m, obj->nbuckets_s1, obj->nbuckets_s2)]; symnum != ELF_SYM_UNDEFINED; symnum = obj->chains[symnum]) { - const Elf_Sym *symp; - const char *strp; - assert(symnum < obj->nchains); - symp = obj->symtab + symnum; - strp = obj->strtab + symp->st_name; - rdbg(("check \"%s\" vs \"%s\" in %s", name, strp, obj->path)); - if (name[1] != strp[1] || strcmp(name, strp)) - continue; -#if defined(__mips__) || defined(__vax__) - if (symp->st_shndx == SHN_UNDEF) - continue; -#else - /* - * XXX DANGER WILL ROBINSON! - * If we have a function pointer in the executable's - * data section, it points to the executable's PLT - * slot, and there is NO relocation emitted. To make - * the function pointer comparable to function pointers - * in shared libraries, we must resolve data references - * in the libraries to point to PLT slots in the - * executable, if they exist. - */ - if (symp->st_shndx == SHN_UNDEF && - ((flags & SYMLOOK_IN_PLT) || - symp->st_value == 0 || - ELF_ST_TYPE(symp->st_info) != STT_FUNC)) - continue; -#endif - if (ventry == NULL) { - if (obj->versyms != NULL) { - verndx = VER_NDX(obj->versyms[symnum].vs_vers); - if (verndx > obj->vertabnum) { - _rtld_error("%s: symbol %s references " - "wrong version %d", obj->path, - &obj->strtab[symnum], verndx); - continue; - } - - /* - * If we are not called from dlsym (i.e. this - * is a normal relocation from unversioned - * binary), accept the symbol immediately - * if it happens to have first version after - * this shared object became versioned. - * Otherwise, if symbol is versioned and not - * hidden, remember it. If it is the only - * symbol with this name exported by the shared - * object, it will be returned as a match at the - * end of the function. If symbol is global - * (verndx < 2) accept it unconditionally. - */ - if (!(flags & SYMLOOK_DLSYM) && - verndx == VER_NDX_GIVEN) { - return symp; - } else if (verndx >= VER_NDX_GIVEN) { - if (!(obj->versyms[symnum].vs_vers & VER_NDX_HIDDEN)) { - if (vsymp == NULL) - vsymp = symp; - vcount++; - } - continue; - } - } - return symp; - } else { - if (obj->versyms == NULL) { - if (_rtld_object_match_name(obj, ventry->name)){ - _rtld_error("%s: object %s should " - "provide version %s for symbol %s", - _rtld_objself.path, obj->path, - ventry->name, &obj->strtab[symnum]); - continue; - } - } else { - verndx = VER_NDX(obj->versyms[symnum].vs_vers); - if (verndx > obj->vertabnum) { - _rtld_error("%s: symbol %s references " - "wrong version %d", obj->path, - &obj->strtab[symnum], verndx); - continue; - } - if (obj->vertab[verndx].hash != ventry->hash || - strcmp(obj->vertab[verndx].name, ventry->name)) { - /* - * Version does not match. Look if this - * is a global symbol and if it is not - * hidden. If global symbol (verndx < 2) - * is available, use it. Do not return - * symbol if we are called by dlvsym, - * because dlvsym looks for a specific - * version and default one is not what - * dlvsym wants. - */ - if ((flags & SYMLOOK_DLSYM) || - (obj->versyms[symnum].vs_vers & VER_NDX_HIDDEN) || - (verndx >= VER_NDX_GIVEN)) - continue; - } - } - return symp; + if (_rtld_symlook_obj_matched_symbol(name, obj, flags, + ventry, symnum, &vsymp, &vcount)) { + return vsymp; } } if (vcount == 1)