diff options
Diffstat (limited to 'elf/dl-lookup.c')
-rw-r--r-- | elf/dl-lookup.c | 304 |
1 files changed, 159 insertions, 145 deletions
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index be6f76faa8..896e1d2771 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -186,6 +186,162 @@ check_match (const char *const undef_name, return sym; } +/* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol + in the unique symbol table, creating a new entry if necessary. + Return the matching symbol in RESULT. */ +static void +do_lookup_unique (const char *undef_name, uint_fast32_t new_hash, + const struct link_map *map, struct sym_val *result, + int type_class, const ElfW(Sym) *sym, const char *strtab, + const ElfW(Sym) *ref, const struct link_map *undef_map) +{ + /* We have to determine whether we already found a + symbol with this name before. If not then we have to + add it to the search table. If we already found a + definition we have to use it. */ + void enter (struct unique_sym *table, size_t size, + unsigned int hash, const char *name, + const ElfW(Sym) *sym, const struct link_map *map) + { + size_t idx = hash % size; + size_t hash2 = 1 + hash % (size - 2); + while (table[idx].name != NULL) + { + idx += hash2; + if (idx >= size) + idx -= size; + } + + table[idx].hashval = hash; + table[idx].name = name; + table[idx].sym = sym; + table[idx].map = map; + } + + struct unique_sym_table *tab + = &GL(dl_ns)[map->l_ns]._ns_unique_sym_table; + + __rtld_lock_lock_recursive (tab->lock); + + struct unique_sym *entries = tab->entries; + size_t size = tab->size; + if (entries != NULL) + { + size_t idx = new_hash % size; + size_t hash2 = 1 + new_hash % (size - 2); + while (1) + { + if (entries[idx].hashval == new_hash + && strcmp (entries[idx].name, undef_name) == 0) + { + if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) + { + /* We possibly have to initialize the central + copy from the copy addressed through the + relocation. */ + result->s = sym; + result->m = (struct link_map *) map; + } + else + { + result->s = entries[idx].sym; + result->m = (struct link_map *) entries[idx].map; + } + __rtld_lock_unlock_recursive (tab->lock); + return; + } + + if (entries[idx].name == NULL) + break; + + idx += hash2; + if (idx >= size) + idx -= size; + } + + if (size * 3 <= tab->n_elements * 4) + { + /* Expand the table. */ +#ifdef RTLD_CHECK_FOREIGN_CALL + /* This must not happen during runtime relocations. */ + assert (!RTLD_CHECK_FOREIGN_CALL); +#endif + size_t newsize = _dl_higher_prime_number (size + 1); + struct unique_sym *newentries + = calloc (sizeof (struct unique_sym), newsize); + if (newentries == NULL) + { + nomem: + __rtld_lock_unlock_recursive (tab->lock); + _dl_fatal_printf ("out of memory\n"); + } + + for (idx = 0; idx < size; ++idx) + if (entries[idx].name != NULL) + enter (newentries, newsize, entries[idx].hashval, + entries[idx].name, entries[idx].sym, + entries[idx].map); + + tab->free (entries); + tab->size = newsize; + size = newsize; + entries = tab->entries = newentries; + tab->free = free; + } + } + else + { +#ifdef RTLD_CHECK_FOREIGN_CALL + /* This must not happen during runtime relocations. */ + assert (!RTLD_CHECK_FOREIGN_CALL); +#endif + +#ifdef SHARED + /* If tab->entries is NULL, but tab->size is not, it means + this is the second, conflict finding, lookup for + LD_TRACE_PRELINKING in _dl_debug_bindings. Don't + allocate anything and don't enter anything into the + hash table. */ + if (__glibc_unlikely (tab->size)) + { + assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK); + goto success; + } +#endif + +#define INITIAL_NUNIQUE_SYM_TABLE 31 + size = INITIAL_NUNIQUE_SYM_TABLE; + entries = calloc (sizeof (struct unique_sym), size); + if (entries == NULL) + goto nomem; + + tab->entries = entries; + tab->size = size; + tab->free = free; + } + + if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) + enter (entries, size, new_hash, strtab + sym->st_name, ref, + undef_map); + else + { + enter (entries, size, new_hash, strtab + sym->st_name, sym, map); + + if (map->l_type == lt_loaded) + /* Make sure we don't unload this object by + setting the appropriate flag. */ + ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE; + } + ++tab->n_elements; + +#ifdef SHARED + success: +#endif + __rtld_lock_unlock_recursive (tab->lock); + + result->s = sym; + result->m = (struct link_map *) map; +} /* Inner part of the lookup functions. We return a value > 0 if we found the symbol, the value 0 if nothing is found and < 0 if @@ -323,157 +479,15 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, } /* FALLTHROUGH */ case STB_GLOBAL: - success: /* Global definition. Just what we need. */ result->s = sym; result->m = (struct link_map *) map; return 1; case STB_GNU_UNIQUE:; - /* We have to determine whether we already found a - symbol with this name before. If not then we have to - add it to the search table. If we already found a - definition we have to use it. */ - void enter (struct unique_sym *table, size_t size, - unsigned int hash, const char *name, - const ElfW(Sym) *sym, const struct link_map *map) - { - size_t idx = hash % size; - size_t hash2 = 1 + hash % (size - 2); - while (table[idx].name != NULL) - { - idx += hash2; - if (idx >= size) - idx -= size; - } - - table[idx].hashval = hash; - table[idx].name = name; - table[idx].sym = sym; - table[idx].map = map; - } - - struct unique_sym_table *tab - = &GL(dl_ns)[map->l_ns]._ns_unique_sym_table; - - __rtld_lock_lock_recursive (tab->lock); - - struct unique_sym *entries = tab->entries; - size_t size = tab->size; - if (entries != NULL) - { - size_t idx = new_hash % size; - size_t hash2 = 1 + new_hash % (size - 2); - while (1) - { - if (entries[idx].hashval == new_hash - && strcmp (entries[idx].name, undef_name) == 0) - { - if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) - { - /* We possibly have to initialize the central - copy from the copy addressed through the - relocation. */ - result->s = sym; - result->m = (struct link_map *) map; - } - else - { - result->s = entries[idx].sym; - result->m = (struct link_map *) entries[idx].map; - } - __rtld_lock_unlock_recursive (tab->lock); - return 1; - } - - if (entries[idx].name == NULL) - break; - - idx += hash2; - if (idx >= size) - idx -= size; - } - - if (size * 3 <= tab->n_elements * 4) - { - /* Expand the table. */ -#ifdef RTLD_CHECK_FOREIGN_CALL - /* This must not happen during runtime relocations. */ - assert (!RTLD_CHECK_FOREIGN_CALL); -#endif - size_t newsize = _dl_higher_prime_number (size + 1); - struct unique_sym *newentries - = calloc (sizeof (struct unique_sym), newsize); - if (newentries == NULL) - { - nomem: - __rtld_lock_unlock_recursive (tab->lock); - _dl_fatal_printf ("out of memory\n"); - } - - for (idx = 0; idx < size; ++idx) - if (entries[idx].name != NULL) - enter (newentries, newsize, entries[idx].hashval, - entries[idx].name, entries[idx].sym, - entries[idx].map); - - tab->free (entries); - tab->size = newsize; - size = newsize; - entries = tab->entries = newentries; - tab->free = free; - } - } - else - { -#ifdef RTLD_CHECK_FOREIGN_CALL - /* This must not happen during runtime relocations. */ - assert (!RTLD_CHECK_FOREIGN_CALL); -#endif - -#ifdef SHARED - /* If tab->entries is NULL, but tab->size is not, it means - this is the second, conflict finding, lookup for - LD_TRACE_PRELINKING in _dl_debug_bindings. Don't - allocate anything and don't enter anything into the - hash table. */ - if (__glibc_unlikely (tab->size)) - { - assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK); - __rtld_lock_unlock_recursive (tab->lock); - goto success; - } -#endif - -#define INITIAL_NUNIQUE_SYM_TABLE 31 - size = INITIAL_NUNIQUE_SYM_TABLE; - entries = calloc (sizeof (struct unique_sym), size); - if (entries == NULL) - goto nomem; - - tab->entries = entries; - tab->size = size; - tab->free = free; - } - - if ((type_class & ELF_RTYPE_CLASS_COPY) != 0) - enter (entries, size, new_hash, strtab + sym->st_name, ref, - undef_map); - else - { - enter (entries, size, new_hash, strtab + sym->st_name, sym, - map); - - if (map->l_type == lt_loaded) - /* Make sure we don't unload this object by - setting the appropriate flag. */ - ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE; - } - ++tab->n_elements; - - __rtld_lock_unlock_recursive (tab->lock); - - goto success; + do_lookup_unique (undef_name, new_hash, map, result, type_class, + sym, strtab, ref, undef_map); + return 1; default: /* Local symbols are ignored. */ |