diff --git a/porting/linux/user/ldso/dynlink.c b/porting/linux/user/ldso/dynlink.c index 9dec2584af93c341818baae94c1172128042708a..1a6fa9dab921d32df413c8fc2070c4dd9cbb8a96 100644 --- a/porting/linux/user/ldso/dynlink.c +++ b/porting/linux/user/ldso/dynlink.c @@ -93,6 +93,11 @@ struct verinfo { uint32_t vna_hash; }; +struct sym_info_pair { + uint_fast32_t sym_h; + uint32_t sym_l; +}; + struct dso { #if DL_FDPIC struct fdpic_loadmap *loadmap; @@ -556,35 +561,42 @@ static int check_verinfo(Verdef *def, int16_t *versym, uint32_t index, struct ve return ret; } -static uint32_t sysv_hash(const char *s0) +static struct sym_info_pair sysv_hash(const char *s0) { + struct sym_info_pair s_info_p; const unsigned char *s = (void *)s0; uint_fast32_t h = 0; while (*s) { h = 16*h + *s++; h ^= h>>24 & 0xf0; } - return h & 0xfffffff; + s_info_p.sym_h = h & 0xfffffff; + s_info_p.sym_l = (char *)s - s0; + return s_info_p; } -static uint32_t gnu_hash(const char *s0) +static struct sym_info_pair gnu_hash(const char *s0) { + struct sym_info_pair s_info_p; const unsigned char *s = (void *)s0; uint_fast32_t h = 5381; for (; *s; s++) h += h*32 + *s; - return h; + s_info_p.sym_h = h; + s_info_p.sym_l = (char *)s - s0; + return s_info_p; } -static Sym *sysv_lookup(struct verinfo *verinfo, uint32_t h, struct dso *dso) +static Sym *sysv_lookup(struct verinfo *verinfo, struct sym_info_pair s_info_p, struct dso *dso) { size_t i; + uint32_t h = s_info_p.sym_h; Sym *syms = dso->syms; Elf_Symndx *hashtab = dso->hashtab; char *strings = dso->strings; for (i=hashtab[2+h%hashtab[0]]; i; i=hashtab[2+hashtab[0]+i]) { if ((!dso->versym || (dso->versym[i] & 0x7fff) >= 0) - && (!strcmp(verinfo->s, strings+syms[i].st_name))) { + && (!memcmp(verinfo->s, strings+syms[i].st_name, s_info_p.sym_l))) { if (!check_verinfo(dso->verdef, dso->versym, i, verinfo, dso->strings)) { continue; } @@ -599,8 +611,9 @@ static Sym *sysv_lookup(struct verinfo *verinfo, uint32_t h, struct dso *dso) return 0; } -static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, struct verinfo *verinfo) +static Sym *gnu_lookup(struct sym_info_pair s_info_p, uint32_t *hashtab, struct dso *dso, struct verinfo *verinfo) { + uint32_t h1 = s_info_p.sym_h; uint32_t nbuckets = hashtab[0]; uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4); uint32_t i = buckets[h1 % nbuckets]; @@ -615,7 +628,7 @@ static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, struct v for (h1 |= 1; ; i++) { uint32_t h2 = *hashval++; if ((h1 == (h2|1)) && (!dso->versym || (dso->versym[i] & 0x7fff) >= 0) - && !strcmp(verinfo->s, dso->strings + dso->syms[i].st_name)) { + && !memcmp(verinfo->s, dso->strings + dso->syms[i].st_name, s_info_p.sym_l)) { if (!check_verinfo(dso->verdef, dso->versym, i, verinfo, dso->strings)) { continue; } @@ -632,9 +645,9 @@ static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, struct v return 0; } -static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, struct dso *dso, struct verinfo *verinfo, uint32_t fofs, size_t fmask) +static Sym *gnu_lookup_filtered(struct sym_info_pair s_info_p, uint32_t *hashtab, struct dso *dso, struct verinfo *verinfo, uint32_t fofs, size_t fmask) { - + uint32_t h1 = s_info_p.sym_h; const size_t *bloomwords = (const void *)(hashtab+4); size_t f = bloomwords[fofs & (hashtab[2]-1)]; if (!(f & fmask)) return 0; @@ -642,7 +655,7 @@ static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, struct dso *dso, f >>= (h1 >> hashtab[3]) % (8 * sizeof f); if (!(f & 1)) return 0; - return gnu_lookup(h1, hashtab, dso, verinfo); + return gnu_lookup(s_info_p, hashtab, dso, verinfo); } static bool check_sym_accessible(struct dso *dso, ns_t *ns) @@ -777,7 +790,8 @@ __attribute__((always_inline)) #endif static inline struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, int need_def, int use_deps, ns_t *ns) { - uint32_t h = 0, gh = gnu_hash(verinfo->s), gho = gh / (8*sizeof(size_t)), *ght; + struct sym_info_pair s_info_p = gnu_hash(verinfo->s); + uint32_t h = 0, gh = s_info_p.sym_h, gho = gh / (8*sizeof(size_t)), *ght; size_t ghm = 1ul << gh % (8*sizeof(size_t)); struct symdef def = {0}; struct dso **deps = use_deps ? dso->deps : 0; @@ -787,10 +801,10 @@ static inline struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, continue; } if ((ght = dso->ghashtab)) { - sym = gnu_lookup_filtered(gh, ght, dso, verinfo, gho, ghm); + sym = gnu_lookup_filtered(s_info_p, ght, dso, verinfo, gho, ghm); } else { - if (!h) h = sysv_hash(verinfo->s); - sym = sysv_lookup(verinfo, h, dso); + if (!h) s_info_p = sysv_hash(verinfo->s); + sym = sysv_lookup(verinfo, s_info_p, dso); } if (!sym) continue; if (!sym->st_shndx) @@ -812,7 +826,8 @@ static inline struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, static inline struct symdef find_sym_by_saved_so_list( int sym_type, struct dso *dso, struct verinfo *verinfo, int need_def, struct dso *dso_relocating) { - uint32_t h = 0, gh = gnu_hash(verinfo->s), gho = gh / (8 * sizeof(size_t)), *ght; + struct sym_info_pair s_info_p = gnu_hash(verinfo->s); + uint32_t h = 0, gh = s_info_p.sym_h, gho = gh / (8 * sizeof(size_t)), *ght; size_t ghm = 1ul << gh % (8 * sizeof(size_t)); struct symdef def = {0}; // skip head dso. @@ -822,10 +837,10 @@ static inline struct symdef find_sym_by_saved_so_list( dso_searching = dso_relocating->reloc_can_search_dso_list[i]; Sym *sym; if ((ght = dso_searching->ghashtab)) { - sym = gnu_lookup_filtered(gh, ght, dso_searching, verinfo, gho, ghm); + sym = gnu_lookup_filtered(s_info_p, ght, dso_searching, verinfo, gho, ghm); } else { - if (!h) h = sysv_hash(verinfo->s); - sym = sysv_lookup(verinfo, h, dso_searching); + if (!h) s_info_p = sysv_hash(verinfo->s); + sym = sysv_lookup(verinfo, s_info_p, dso_searching); } if (!sym) continue; if (!sym->st_shndx)