diff options
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/dynlink.c | 97 |
1 files changed, 53 insertions, 44 deletions
diff --git a/ldso/dynlink.c b/ldso/dynlink.c index d00827a3..0e394e0d 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -58,11 +58,11 @@ struct dso { uint32_t *ghashtab; int16_t *versym; char *strings; + struct dso *syms_next; unsigned char *map; size_t map_len; dev_t dev; ino_t ino; - signed char global; char relocated; char constructed; char kernel_mapped; @@ -113,7 +113,7 @@ static struct builtin_tls { static size_t *saved_addends, *apply_addends_to; static struct dso ldso; -static struct dso *head, *tail, *fini_head; +static struct dso *head, *tail, *fini_head, *syms_tail; static char *env_path, *sys_path; static unsigned long long gencnt; static int runtime; @@ -261,9 +261,8 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def) uint32_t h = 0, gh, gho, *ght; size_t ghm = 0; struct symdef def = {0}; - for (; dso; dso=dso->next) { + for (; dso; dso=dso->syms_next) { Sym *sym; - if (!dso->global) continue; if ((ght = dso->ghashtab)) { if (!ghm) { gh = gnu_hash(s); @@ -329,7 +328,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri if (sym_index) { sym = syms + sym_index; name = strings + sym->st_name; - ctx = type==REL_COPY ? head->next : head; + ctx = type==REL_COPY ? head->syms_next : head; def = (sym->st_info&0xf) == STT_SECTION ? (struct symdef){ .dso = dso, .sym = sym } : find_sym(ctx, name, type==REL_PLT); @@ -932,7 +931,7 @@ static struct dso *load_library(const char *name, struct dso *needed_by) if (!ldso.prev) { tail->next = &ldso; ldso.prev = tail; - tail = ldso.next ? ldso.next : &ldso; + tail = &ldso; } return &ldso; } @@ -1113,9 +1112,24 @@ static void load_preload(char *s) } } -static void make_global(struct dso *p) +static void add_syms(struct dso *p) { - for (; p; p=p->next) p->global = 1; + if (!p->syms_next && syms_tail != p) { + syms_tail->syms_next = p; + syms_tail = p; + } +} + +static void revert_syms(struct dso *old_tail) +{ + struct dso *p, *next; + /* Chop off the tail of the list of dsos that participate in + * the global symbol table, reverting them to RTLD_LOCAL. */ + for (p=old_tail; p; p=next) { + next = p->syms_next; + p->syms_next = 0; + } + syms_tail = old_tail; } static void do_mips_relocs(struct dso *p, size_t *got) @@ -1344,7 +1358,6 @@ void __dls2(unsigned char *base, size_t *sp) } Ehdr *ehdr = (void *)ldso.base; ldso.name = ldso.shortname = "libc.so"; - ldso.global = 1; ldso.phnum = ehdr->e_phnum; ldso.phdr = laddr(&ldso, ehdr->e_phoff); ldso.phentsize = ehdr->e_phentsize; @@ -1532,7 +1545,6 @@ _Noreturn void __dls3(size_t *sp) #endif tls_align = MAXP2(tls_align, app.tls.align); } - app.global = 1; decode_dyn(&app); if (DL_FDPIC) { makefuncdescs(&app); @@ -1547,7 +1559,21 @@ _Noreturn void __dls3(size_t *sp) argv[-3] = (void *)app.loadmap; } - /* Attach to vdso, if provided by the kernel */ + /* Initial dso chain consists only of the app. */ + head = tail = syms_tail = &app; + + /* Donate unused parts of app and library mapping to malloc */ + reclaim_gaps(&app); + reclaim_gaps(&ldso); + + /* Load preload/needed libraries, add symbols to global namespace. */ + if (env_preload) load_preload(env_preload); + load_deps(&app); + for (struct dso *p=head; p; p=p->next) + add_syms(p); + + /* Attach to vdso, if provided by the kernel, last so that it does + * not become part of the global namespace. */ if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR) && vdso_base) { Ehdr *ehdr = (void *)vdso_base; Phdr *phdr = vdso.phdr = (void *)(vdso_base + ehdr->e_phoff); @@ -1561,26 +1587,13 @@ _Noreturn void __dls3(size_t *sp) } vdso.name = ""; vdso.shortname = "linux-gate.so.1"; - vdso.global = 1; vdso.relocated = 1; decode_dyn(&vdso); - vdso.prev = &ldso; - ldso.next = &vdso; + vdso.prev = tail; + tail->next = &vdso; + tail = &vdso; } - /* Initial dso chain consists only of the app. */ - head = tail = &app; - - /* Donate unused parts of app and library mapping to malloc */ - reclaim_gaps(&app); - reclaim_gaps(&ldso); - - /* Load preload/needed libraries, add their symbols to the global - * namespace, and perform all remaining relocations. */ - if (env_preload) load_preload(env_preload); - load_deps(&app); - make_global(&app); - for (i=0; app.dynv[i]; i+=2) { if (!DT_DEBUG_INDIRECT && app.dynv[i]==DT_DEBUG) app.dynv[i+1] = (size_t)&debug; @@ -1641,7 +1654,7 @@ _Noreturn void __dls3(size_t *sp) void *dlopen(const char *file, int mode) { - struct dso *volatile p, *orig_tail, *next; + struct dso *volatile p, *orig_tail, *orig_syms_tail, *next; struct tls_module *orig_tls_tail; size_t orig_tls_cnt, orig_tls_offset, orig_tls_align; size_t i; @@ -1659,15 +1672,14 @@ void *dlopen(const char *file, int mode) orig_tls_cnt = tls_cnt; orig_tls_offset = tls_offset; orig_tls_align = tls_align; + orig_syms_tail = syms_tail; orig_tail = tail; noload = mode & RTLD_NOLOAD; rtld_fail = &jb; if (setjmp(*rtld_fail)) { /* Clean up anything new that was (partially) loaded */ - if (p && p->deps) for (i=0; p->deps[i]; i++) - if (p->deps[i]->global < 0) - p->deps[i]->global = 0; + revert_syms(orig_syms_tail); for (p=orig_tail->next; p; p=next) { next = p->next; while (p->td_index) { @@ -1703,24 +1715,21 @@ void *dlopen(const char *file, int mode) } /* First load handling */ - if (!p->deps) { + if (!p->relocated) { load_deps(p); + /* Make new symbols global, at least temporarily, so we can do + * relocations. If not RTLD_GLOBAL, this is reverted below. */ + add_syms(p); if (p->deps) for (i=0; p->deps[i]; i++) - if (!p->deps[i]->global) - p->deps[i]->global = -1; - if (!p->global) p->global = -1; + add_syms(p->deps[i]); reloc_all(p); - if (p->deps) for (i=0; p->deps[i]; i++) - if (p->deps[i]->global < 0) - p->deps[i]->global = 0; - if (p->global < 0) p->global = 0; } - if (mode & RTLD_GLOBAL) { - if (p->deps) for (i=0; p->deps[i]; i++) - p->deps[i]->global = 1; - p->global = 1; - } + /* If RTLD_GLOBAL was not specified, undo any new additions + * to the global symbol table. This is a nop if the library was + * previously loaded and already global. */ + if (!(mode & RTLD_GLOBAL)) + revert_syms(orig_syms_tail); update_tls_size(); _dl_debug_state(); |