summaryrefslogtreecommitdiff
path: root/ldso/ldso/dl-hash.c
diff options
context:
space:
mode:
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>2010-07-29 11:35:05 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2010-09-17 16:07:25 +0200
commit94cc6edb78a12655c0602a246fa1cbdc8c6d0ad9 (patch)
tree4dcffeee2396c0cd7d7b30f5a493c31ad7e171ad /ldso/ldso/dl-hash.c
parent637e2b2440f69e22932edd71bd2f0b1210dc32ea (diff)
ldso: Rework global scope handling and symbol lookup mechanism
Global symbol scope is implemented as a linked list of local scope, that dynamically grows and shrinks when dlopen/ dlclose are called. Each local scope is implemented as an array of pointer to struct elf_resolve. This will help to detect conflict when LD_TRACE_PRELINKING option will be implemented. Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com> Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Diffstat (limited to 'ldso/ldso/dl-hash.c')
-rw-r--r--ldso/ldso/dl-hash.c83
1 files changed, 44 insertions, 39 deletions
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index 0048734ba..2c4571f20 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -268,70 +268,75 @@ _dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long
* This function resolves externals, and this is either called when we process
* relocations or when we call an entry in the PLT table for the first time.
*/
-char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt,
+char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
int type_class, struct elf_resolve **tpntp)
{
struct elf_resolve *tpnt = NULL;
ElfW(Sym) *symtab;
+ int i = 0;
unsigned long elf_hash_number = 0xffffffff;
const ElfW(Sym) *sym = NULL;
char *weak_result = NULL;
+ struct r_scope_elem *loop_scope;
#ifdef __LDSO_GNU_HASH_SUPPORT__
unsigned long gnu_hash_number = _dl_gnu_hash((const unsigned char *)name);
#endif
- for (; rpnt; rpnt = rpnt->next) {
- tpnt = rpnt->dyn;
-
- if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
- if (mytpnt == tpnt)
- ;
- else {
- struct init_fini_list *tmp;
-
- for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
- if (tmp->tpnt == tpnt)
- break;
+ for (loop_scope = scope; loop_scope && !sym; loop_scope = loop_scope->next) {
+ for (i = 0; i < loop_scope->r_nlist; i++) {
+ tpnt = loop_scope->r_list[i];
+
+ if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
+ if (mytpnt == tpnt)
+ ;
+ else {
+ struct init_fini_list *tmp;
+
+ for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
+ if (tmp->tpnt == tpnt)
+ break;
+ }
+ if (!tmp)
+ continue;
}
- if (!tmp)
- continue;
}
- }
- /* Don't search the executable when resolving a copy reloc. */
- if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
- continue;
+ /* Don't search the executable when resolving a copy reloc. */
+ if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
+ continue;
- /* If the hash table is empty there is nothing to do here. */
- if (tpnt->nbucket == 0)
- continue;
+ /* If the hash table is empty there is nothing to do here. */
+ if (tpnt->nbucket == 0)
+ continue;
- symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
+ symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
#ifdef __LDSO_GNU_HASH_SUPPORT__
- /* Prefer GNU hash style, if any */
- if (tpnt->l_gnu_bitmask) {
- sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class);
- if (sym != NULL)
- /* If sym has been found, do not search further */
- break;
- } else {
+ /* Prefer GNU hash style, if any */
+ if (tpnt->l_gnu_bitmask) {
+ sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class);
+ if (sym != NULL)
+ /* If sym has been found, do not search further */
+ break;
+ } else {
#endif
- /* Use the old SysV-style hash table */
+ /* Use the old SysV-style hash table */
- /* Calculate the old sysv hash number only once */
- if (elf_hash_number == 0xffffffff)
- elf_hash_number = _dl_elf_hash((const unsigned char *)name);
+ /* Calculate the old sysv hash number only once */
+ if (elf_hash_number == 0xffffffff)
+ elf_hash_number = _dl_elf_hash((const unsigned char *)name);
- sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class);
- if (sym != NULL)
- break;
+ sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class);
+ if (sym != NULL)
+ /* If sym has been found, do not search further */
+ break;
#ifdef __LDSO_GNU_HASH_SUPPORT__
- }
+ }
#endif
- } /* end of for (; rpnt; rpnt = rpnt->next) { */
+ } /* End of inner for */
+ }
if (sym) {
/* At this point we have found the requested symbol, do binding */