diff options
author | Filippo Arcidiacono <filippo.arcidiacono@st.com> | 2010-07-29 11:35:05 +0200 |
---|---|---|
committer | Carmelo Amoroso <carmelo.amoroso@st.com> | 2010-09-17 16:07:25 +0200 |
commit | 94cc6edb78a12655c0602a246fa1cbdc8c6d0ad9 (patch) | |
tree | 4dcffeee2396c0cd7d7b30f5a493c31ad7e171ad /ldso/ldso | |
parent | 637e2b2440f69e22932edd71bd2f0b1210dc32ea (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')
-rw-r--r-- | ldso/ldso/dl-elf.c | 9 | ||||
-rw-r--r-- | ldso/ldso/dl-hash.c | 83 | ||||
-rw-r--r-- | ldso/ldso/dl-startup.c | 2 | ||||
-rw-r--r-- | ldso/ldso/ldso.c | 78 | ||||
-rw-r--r-- | ldso/ldso/sh/elfinterp.c | 14 |
5 files changed, 122 insertions, 64 deletions
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 2a77587db..a8ccc5e91 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -814,7 +814,6 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, } #endif (*rpnt)->dyn = tpnt; - tpnt->symbol_scope = _dl_symbol_tables; tpnt->usage_count++; #ifdef __LDSO_STANDALONE_SUPPORT__ tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable; @@ -846,7 +845,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, } /* now_flag must be RTLD_NOW or zero */ -int _dl_fixup(struct dyn_elf *rpnt, int now_flag) +int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag) { int goof = 0; struct elf_resolve *tpnt; @@ -854,7 +853,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag) ElfW(Addr) reloc_addr; if (rpnt->next) - goof = _dl_fixup(rpnt->next, now_flag); + goof = _dl_fixup(rpnt->next, scope, now_flag); if (goof) return goof; tpnt = rpnt->dyn; @@ -884,7 +883,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag) elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count); reloc_addr += relative_count * sizeof(ELF_RELOC); } - goof += _dl_parse_relocation_information(rpnt, + goof += _dl_parse_relocation_information(rpnt, scope, reloc_addr, reloc_size); tpnt->init_flag |= RELOCS_DONE; @@ -900,7 +899,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag) tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info [DT_PLTRELSZ]); } else { - goof += _dl_parse_relocation_information(rpnt, + goof += _dl_parse_relocation_information(rpnt, scope, tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ]); } 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 */ diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c index 2aefa6d74..feffa787b 100644 --- a/ldso/ldso/dl-startup.c +++ b/ldso/ldso/dl-startup.c @@ -192,7 +192,7 @@ DL_START(unsigned long args) DL_BOOT_COMPUTE_GOT(got); /* Now, finally, fix up the location of the dynamic stuff */ - DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr); + DL_BOOT_COMPUTE_DYN(dpnt, got, (DL_LOADADDR_TYPE)header); SEND_EARLY_STDERR_DEBUG("First Dynamic section entry="); SEND_ADDRESS_STDERR_DEBUG(dpnt, 1); diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index bb394714f..ff3519f7c 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -107,6 +107,7 @@ static unsigned char *_dl_malloc_addr = NULL; /* Lets _dl_malloc use the already static unsigned char *_dl_mmap_zero = NULL; /* Also used by _dl_malloc */ static struct elf_resolve **init_fini_list; +static struct elf_resolve **scope_elem_list; static unsigned int nlist; /* # items in init_fini_list */ extern void _start(void); @@ -284,6 +285,21 @@ static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void) } } +static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list, + struct elf_resolve *map) +{ + struct elf_resolve **p = list; + struct init_fini_list *q; + + *p++ = map; + map->init_flag |= DL_RESERVED; + if (map->init_fini) + for (q = map->init_fini; q; q = q->next) + if (! (q->tpnt->init_flag & DL_RESERVED)) + p += _dl_build_local_scope (p, q->tpnt); + return p - list; +} + void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv DL_GET_READY_TO_RUN_EXTRA_PARMS) @@ -292,7 +308,7 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, ElfW(Phdr) *ppnt; ElfW(Dyn) *dpnt; char *lpntstr; - unsigned int i; + unsigned int i, cnt, k, nscope_elem; int unlazy = 0, trace_loaded_objects = 0; struct dyn_elf *rpnt; struct elf_resolve *tcurr; @@ -304,6 +320,9 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, unsigned long *_dl_envp; /* The environment address */ ElfW(Addr) relro_addr = 0; size_t relro_size = 0; + struct r_scope_elem *global_scope; + struct elf_resolve **local_scope; + struct stat st; #if defined(USE_TLS) && USE_TLS void *tcbp = NULL; @@ -576,7 +595,6 @@ of this helper program; chances are you did not intend to run this program.\n\ app_tpnt->mapaddr = app_mapaddr; app_tpnt->rtld_flags = unlazy | RTLD_GLOBAL; app_tpnt->usage_count++; - app_tpnt->symbol_scope = _dl_symbol_tables; lpnt = (unsigned long *) (app_tpnt->dynamic_info[DT_PLTGOT]); #ifdef ALLOW_ZERO_PLTGOT if (lpnt) @@ -637,11 +655,11 @@ of this helper program; chances are you did not intend to run this program.\n\ * case the executable is actually an ET_DYN object. */ if (app_tpnt->l_tls_initimage != NULL) { + unsigned int tmp = (unsigned int) app_tpnt->l_tls_initimage; app_tpnt->l_tls_initimage = (char *) app_tpnt->l_tls_initimage + app_tpnt->loadaddr; _dl_debug_early("Relocated TLS initial image from %x to %x (size = %x)\n", - (unsigned int)app_tpnt->l_tls_initimage, - app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size); + tmp, app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size); } #endif @@ -926,6 +944,9 @@ of this helper program; chances are you did not intend to run this program.\n\ } _dl_unmap_cache(); + /* Keep track of the number of elements in the global scope */ + nscope_elem = nlist; + --nlist; /* Exclude the application. */ init_fini_list = _dl_malloc(nlist * sizeof(struct elf_resolve *)); i = 0; @@ -1002,7 +1023,7 @@ of this helper program; chances are you did not intend to run this program.\n\ } tpnt->libtype = program_interpreter; tpnt->usage_count++; - tpnt->symbol_scope = _dl_symbol_tables; + nscope_elem++; if (rpnt) { rpnt->next = _dl_zalloc(sizeof(struct dyn_elf)); rpnt->next->prev = rpnt; @@ -1012,6 +1033,7 @@ of this helper program; chances are you did not intend to run this program.\n\ } rpnt->dyn = tpnt; tpnt->rtld_flags = RTLD_NOW | RTLD_GLOBAL; /* Must not be LAZY */ + #ifdef RERELOCATE_LDSO /* Only rerelocate functions for now. */ tpnt->init_flag = RELOCS_DONE; @@ -1026,6 +1048,38 @@ of this helper program; chances are you did not intend to run this program.\n\ tpnt = NULL; } + /* + * Allocate the global scope array. + */ + scope_elem_list = (struct elf_resolve **) _dl_malloc(nscope_elem * sizeof(struct elf_resolve *)); + + for (i = 0, tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) + scope_elem_list[i++] = tcurr; + + _dl_loaded_modules->symbol_scope.r_list = scope_elem_list; + _dl_loaded_modules->symbol_scope.r_nlist = nscope_elem; + /* + * The symbol scope of the application, that is the first entry of the + * _dl_loaded_modules list, is just the global scope to be used for the + * symbol lookup. + */ + global_scope = &_dl_loaded_modules->symbol_scope; + + /* Build the local scope for the each loaded modules. */ + local_scope = _dl_malloc(nscope_elem * sizeof(struct elf_resolve *)); + i = 1; + for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) { + cnt = _dl_build_local_scope(local_scope, scope_elem_list[i++]); + tcurr->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *)); + tcurr->symbol_scope.r_nlist = cnt; + _dl_memcpy (tcurr->symbol_scope.r_list, local_scope, cnt * sizeof (struct elf_resolve *)); + /* Restoring the init_flag.*/ + for (k = 1; k < nscope_elem; k++) + scope_elem_list[k]->init_flag &= ~DL_RESERVED; + } + + _dl_free(local_scope); + #ifdef __LDSO_LDD_SUPPORT__ /* End of the line for ldd.... */ if (trace_loaded_objects) { @@ -1081,7 +1135,7 @@ of this helper program; chances are you did not intend to run this program.\n\ * order so that COPY directives work correctly. */ if (_dl_symbol_tables) - if (_dl_fixup(_dl_symbol_tables, unlazy)) + if (_dl_fixup(_dl_symbol_tables, global_scope, unlazy)) _dl_exit(-1); for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { @@ -1118,7 +1172,7 @@ of this helper program; chances are you did not intend to run this program.\n\ * ld.so.1, so we have to look up each symbol individually. */ - _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", _dl_symbol_tables, NULL, 0, NULL); + _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", global_scope, NULL, 0, NULL); if (_dl_envp) *_dl_envp = (unsigned long) envp; @@ -1174,21 +1228,21 @@ of this helper program; chances are you did not intend to run this program.\n\ /* Find the real malloc function and make ldso functions use that from now on */ _dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "malloc", - _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL); + global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL); #if defined(USE_TLS) && USE_TLS /* Find the real functions and make ldso functions use them from now on */ _dl_calloc_function = (void* (*)(size_t, size_t)) (intptr_t) - _dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL); + _dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL); _dl_realloc_function = (void* (*)(void *, size_t)) (intptr_t) - _dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL); + _dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL); _dl_free_function = (void (*)(void *)) (intptr_t) - _dl_find_hash(__C_SYMBOL_PREFIX__ "free", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL); + _dl_find_hash(__C_SYMBOL_PREFIX__ "free", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL); _dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t) - _dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL); + _dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL); #endif diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c index 715eadc15..d3465bcd5 100644 --- a/ldso/ldso/sh/elfinterp.c +++ b/ldso/ldso/sh/elfinterp.c @@ -69,7 +69,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) got_addr = (char **) instr_addr; /* Get the address of the GOT entry */ - new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); + new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); if (unlikely(!new_addr)) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); @@ -95,9 +95,9 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) static int -_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size, - int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope, + int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) { unsigned int i; @@ -148,7 +148,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, static int -_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, +_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { int reloc_type; @@ -251,7 +251,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, static int -_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) { int reloc_type; @@ -293,7 +293,7 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, } int _dl_parse_relocation_information(struct dyn_elf *rpnt, - unsigned long rel_addr, unsigned long rel_size) + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) { - return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc); + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } |