未验证 提交 9959e363 编写于 作者: O openharmony_ci 提交者: Gitee

!899 Optimize dladdr performance

Merge pull request !899 from yinchuang/opt_dladdr
......@@ -105,7 +105,7 @@ struct reserved_address_params {
#endif
};
typedef void (*stage3_func)(size_t *, size_t *);
typedef void (*stage3_func)(size_t *, size_t *, size_t *);
static struct builtin_tls {
char c[8];
......@@ -2609,6 +2609,9 @@ hidden void __dls2(unsigned char *base, size_t *sp)
} else {
ldso.base = base;
}
size_t aux[AUX_CNT];
decode_vec(auxv, aux, AUX_CNT);
libc.page_size = aux[AT_PAGESZ];
Ehdr *ehdr = (void *)ldso.base;
ldso.name = ldso.shortname = "libc.so";
ldso.phnum = ehdr->e_phnum;
......@@ -2645,8 +2648,8 @@ hidden void __dls2(unsigned char *base, size_t *sp)
* symbolically as a barrier against moving the address
* load across the above relocation processing. */
struct symdef dls2b_def = find_sym(&ldso, "__dls2b", 0);
if (DL_FDPIC) ((stage3_func)&ldso.funcdescs[dls2b_def.sym-ldso.syms])(sp, auxv);
else ((stage3_func)laddr(&ldso, dls2b_def.sym->st_value))(sp, auxv);
if (DL_FDPIC) ((stage3_func)&ldso.funcdescs[dls2b_def.sym-ldso.syms])(sp, auxv, aux);
else ((stage3_func)laddr(&ldso, dls2b_def.sym->st_value))(sp, auxv, aux);
}
/* Stage 2b sets up a valid thread pointer, which requires relocations
......@@ -2655,7 +2658,7 @@ hidden void __dls2(unsigned char *base, size_t *sp)
* so that loads of the thread pointer and &errno can be pure/const and
* thereby hoistable. */
void __dls2b(size_t *sp, size_t *auxv)
void __dls2b(size_t *sp, size_t *auxv, size_t *aux)
{
/* Setup early thread pointer in builtin_tls for ldso/libc itself to
* use during dynamic linking. If possible it will also serve as the
......@@ -2669,8 +2672,8 @@ void __dls2b(size_t *sp, size_t *auxv)
}
struct symdef dls3_def = find_sym(&ldso, "__dls3", 0);
if (DL_FDPIC) ((stage3_func)&ldso.funcdescs[dls3_def.sym-ldso.syms])(sp, auxv);
else ((stage3_func)laddr(&ldso, dls3_def.sym->st_value))(sp, auxv);
if (DL_FDPIC) ((stage3_func)&ldso.funcdescs[dls3_def.sym-ldso.syms])(sp, auxv, aux);
else ((stage3_func)laddr(&ldso, dls3_def.sym->st_value))(sp, auxv, aux);
}
/* Stage 3 of the dynamic linker is called with the dynamic linker/libc
......@@ -2678,10 +2681,9 @@ void __dls2b(size_t *sp, size_t *auxv)
* process dependencies and relocations for the main application and
* transfer control to its entry point. */
void __dls3(size_t *sp, size_t *auxv)
void __dls3(size_t *sp, size_t *auxv, size_t *aux)
{
static struct dso app, vdso;
size_t aux[AUX_CNT];
size_t i;
char *env_preload=0;
char *replace_argv0=0;
......@@ -2694,10 +2696,8 @@ void __dls3(size_t *sp, size_t *auxv)
/* Find aux vector just past environ[] and use it to initialize
* global data that may be needed before we can make syscalls. */
__environ = envp;
decode_vec(auxv, aux, AUX_CNT);
search_vec(auxv, &__sysinfo, AT_SYSINFO);
__pthread_self()->sysinfo = __sysinfo;
libc.page_size = aux[AT_PAGESZ];
libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
|| aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]);
......@@ -3511,31 +3511,19 @@ void *addr2dso(size_t a)
{
struct dso *p;
size_t i;
if (DL_FDPIC) for (p=head; p; p=p->next) {
i = count_syms(p);
if (a-(size_t)p->funcdescs < i*sizeof(*p->funcdescs))
return p;
}
for (p=head; p; p=p->next) {
if (DL_FDPIC && p->loadmap) {
for (i=0; i<p->loadmap->nsegs; i++) {
if (a-p->loadmap->segs[i].p_vaddr
< p->loadmap->segs[i].p_memsz)
return p;
}
} else {
Phdr *ph = p->phdr;
size_t phcnt = p->phnum;
size_t entsz = p->phentsize;
size_t base = (size_t)p->base;
for (; phcnt--; ph=(void *)((char *)ph+entsz)) {
if (ph->p_type != PT_LOAD) continue;
if (a-base-ph->p_vaddr < ph->p_memsz)
return p;
}
if (a-(size_t)p->map < p->map_len)
return 0;
if (a < p->map || a - (size_t)p->map >= p->map_len) continue;
Phdr *ph = p->phdr;
size_t phcnt = p->phnum;
size_t entsz = p->phentsize;
size_t base = (size_t)p->base;
for (; phcnt--; ph=(void *)((char *)ph+entsz)) {
if (ph->p_type != PT_LOAD) continue;
if (a-base-ph->p_vaddr < ph->p_memsz)
return p;
}
if (a-(size_t)p->map < p->map_len)
return 0;
}
return 0;
}
......@@ -3777,15 +3765,71 @@ hidden int __dlclose(void *p)
return rc;
}
static inline int sym_is_matched(const Sym* sym, size_t addr_offset_so) {
return sym->st_value &&
(1<<(sym->st_info&0xf) != STT_TLS) &&
(addr_offset_so >= sym->st_value) &&
(addr_offset_so < sym->st_value + sym->st_size);
}
static inline Sym* find_addr_by_elf(size_t addr_offset_so, struct dso *p) {
uint32_t nsym = p->hashtab[1];
Sym *sym = p->syms;
for (; nsym; nsym--, sym++) {
if (sym_is_matched(sym, addr_offset_so)) {
return sym;
}
}
return NULL;
}
static inline Sym* find_addr_by_gnu(size_t addr_offset_so, struct dso *p) {
size_t i, nsym, first_hash_sym_index;
uint32_t *hashval;
Sym *sym_tab = p->syms;
uint32_t *buckets= p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4);
// Points to the first defined symbol, all symbols before it are undefined.
first_hash_sym_index = buckets[0];
Sym *sym = &sym_tab[first_hash_sym_index];
// Get the location pointed by the last bucket.
for (i = nsym = 0; i < p->ghashtab[0]; i++) {
if (buckets[i] > nsym)
nsym = buckets[i];
}
for (i = first_hash_sym_index; i < nsym; i++) {
if (sym_is_matched(sym, addr_offset_so)) {
return sym;
}
sym++;
}
// Start traversing the hash list from the position pointed to by the last bucket.
if (nsym) {
hashval = buckets + p->ghashtab[0] + (nsym - p->ghashtab[1]);
do {
nsym++;
if (sym_is_matched(sym, addr_offset_so)) {
return sym;
}
sym++;
}
while (!(*hashval++ & 1));
}
return NULL;
}
int dladdr(const void *addr_arg, Dl_info *info)
{
size_t addr = (size_t)addr_arg;
struct dso *p;
Sym *sym, *bestsym;
uint32_t nsym;
Sym *match_sym = NULL;
char *strings;
size_t best = 0;
size_t besterr = -1;
pthread_rwlock_rdlock(&lock);
p = addr2dso(addr);
......@@ -3793,54 +3837,26 @@ int dladdr(const void *addr_arg, Dl_info *info)
if (!p) return 0;
sym = p->syms;
strings = p->strings;
nsym = count_syms(p);
size_t addr_offset_so = addr - (size_t)p->base;
if (DL_FDPIC) {
size_t idx = (addr-(size_t)p->funcdescs)
/ sizeof(*p->funcdescs);
if (idx < nsym && (sym[idx].st_info&0xf) == STT_FUNC) {
best = (size_t)(p->funcdescs + idx);
bestsym = sym + idx;
besterr = 0;
}
}
info->dli_fname = p->name;
info->dli_fbase = p->map;
if (!best) for (; nsym; nsym--, sym++) {
if (sym->st_value
&& (1<<(sym->st_info&0xf) & OK_TYPES)
&& (1<<(sym->st_info>>4) & OK_BINDS)) {
size_t symaddr = (size_t)laddr(p, sym->st_value);
if (symaddr > addr || symaddr <= best)
continue;
best = symaddr;
bestsym = sym;
besterr = addr - symaddr;
if (addr == symaddr)
break;
}
}
if (p->ghashtab) {
match_sym = find_addr_by_gnu(addr_offset_so, p);
if (best && besterr > bestsym->st_size-1) {
best = 0;
bestsym = 0;
} else {
match_sym = find_addr_by_elf(addr_offset_so, p);
}
info->dli_fname = p->name;
info->dli_fbase = p->map;
if (!best) {
if (!match_sym) {
info->dli_sname = 0;
info->dli_saddr = 0;
return 1;
}
if (DL_FDPIC && (bestsym->st_info&0xf) == STT_FUNC)
best = (size_t)(p->funcdescs + (bestsym - p->syms));
info->dli_sname = strings + bestsym->st_name;
info->dli_saddr = (void *)best;
info->dli_sname = strings + match_sym->st_name;
info->dli_saddr = (void *)laddr(p, match_sym->st_value);
return 1;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册