diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2018-11-16 05:05:45 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2018-11-16 05:05:45 +0000 |
commit | ea22d965aca91aeddadc1990aa32b9cddcbb5590 (patch) | |
tree | 132ebb8cf436c3e3650d96526128aa03ec3f1416 /libexec/ld.so/resolve.c | |
parent | b5d0e90b465658522c751633dcc820f79b9ce163 (diff) |
Borrow an idea from DragonFly BSD: factor out the "does this symbol match what
we're looking up?" logic from _dl_find_symbol_obj() into matched_symbol(), so
that the former is just the "iterate across the hash" logic.
matched_symbol() returns zero on "not found", one on "found strong
symbol", and negative one on "found weak symbol". The last of those lets
the caller give up on this object after finding a weak symbol, as there's
no point in continuing to search for a strong symbol in the same object.
ok mpi@
Diffstat (limited to 'libexec/ld.so/resolve.c')
-rw-r--r-- | libexec/ld.so/resolve.c | 92 |
1 files changed, 54 insertions, 38 deletions
diff --git a/libexec/ld.so/resolve.c b/libexec/ld.so/resolve.c index ab2a8f9ecf6..0f192982d00 100644 --- a/libexec/ld.so/resolve.c +++ b/libexec/ld.so/resolve.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resolve.c,v 1.84 2018/11/15 21:25:44 guenther Exp $ */ +/* $OpenBSD: resolve.c,v 1.85 2018/11/16 05:05:44 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -590,52 +590,68 @@ _dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx, } static int +matched_symbol(elf_object_t *obj, const Elf_Sym *sym, struct symlookup *sl) +{ + switch (ELF_ST_TYPE(sym->st_info)) { + case STT_FUNC: + /* + * Allow this symbol if we are referring to a function which + * has a value, even if section is UNDEF. This allows &func + * to refer to PLT as per the ELF spec. If flags has SYM_PLT + * set, we must have actual symbol, so this symbol is skipped. + */ + if ((sl->sl_flags & SYM_PLT) && sym->st_shndx == SHN_UNDEF) + return 0; + if (sym->st_value == 0) + return 0; + break; + case STT_NOTYPE: + case STT_OBJECT: + if (sym->st_value == 0) + return 0; +#if 0 + /* FALLTHROUGH */ + case STT_TLS: +#endif + if (sym->st_shndx == SHN_UNDEF) + return 0; + break; + default: + return 0; + } + + if (sym != sl->sl_sym_out && + _dl_strcmp(sl->sl_name, obj->dyn.strtab + sym->st_name)) + return 0; + + if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { + sl->sl_sym_out = sym; + sl->sl_obj_out = obj; + return 1; + } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { + if (sl->sl_weak_sym_out == NULL) { + sl->sl_weak_sym_out = sym; + sl->sl_weak_obj_out = obj; + } + /* done with this object, but need to check other objects */ + return -1; + } + return 0; +} + +static int _dl_find_symbol_obj(elf_object_t *obj, struct symlookup *sl) { const Elf_Sym *symt = obj->dyn.symtab; - const char *strt = obj->dyn.strtab; long si; - const char *symn; for (si = obj->buckets[sl->sl_elf_hash % obj->nbuckets]; si != STN_UNDEF; si = obj->chains[si]) { const Elf_Sym *sym = symt + si; - if (sym->st_value == 0) - continue; - - if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE && - ELF_ST_TYPE(sym->st_info) != STT_OBJECT && - ELF_ST_TYPE(sym->st_info) != STT_FUNC) - continue; - - symn = strt + sym->st_name; - if (sym != sl->sl_sym_out && _dl_strcmp(symn, sl->sl_name)) - continue; - - /* allow this symbol if we are referring to a function - * which has a value, even if section is UNDEF. - * this allows &func to refer to PLT as per the - * ELF spec. st_value is checked above. - * if flags has SYM_PLT set, we must have actual - * symbol, so this symbol is skipped. - */ - if (sym->st_shndx == SHN_UNDEF) { - if ((sl->sl_flags & SYM_PLT) || sym->st_value == 0 || - ELF_ST_TYPE(sym->st_info) != STT_FUNC) - continue; - } - - if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) { - sl->sl_sym_out = sym; - sl->sl_obj_out = obj; - return 1; - } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { - if (sl->sl_weak_sym_out == NULL) { - sl->sl_weak_sym_out = sym; - sl->sl_weak_obj_out = obj; - } - } + int r = matched_symbol(obj, sym, sl); + if (r) + return r > 0; } return 0; } |