diff options
author | Timo Teräs <timo.teras@iki.fi> | 2017-03-21 15:17:26 +0200 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2017-03-21 15:27:08 +0200 |
commit | dd232808d24fb6cba3f06117f5e974effd3051c7 (patch) | |
tree | d956a5df2228b1710bd64648e8f05bda2d3d9d8f /main/musl/0016-rework-ldso-handling-of-global-symbol-table-for-cons.patch | |
parent | ebada60098b1cfc0d1f7a21bdd3e7ed27af2f873 (diff) | |
download | aports-dd232808d24fb6cba3f06117f5e974effd3051c7.tar.bz2 aports-dd232808d24fb6cba3f06117f5e974effd3051c7.tar.xz |
main/musl: cherry-pick ldso improvements and lazy relocation emulation
Diffstat (limited to 'main/musl/0016-rework-ldso-handling-of-global-symbol-table-for-cons.patch')
-rw-r--r-- | main/musl/0016-rework-ldso-handling-of-global-symbol-table-for-cons.patch | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/main/musl/0016-rework-ldso-handling-of-global-symbol-table-for-cons.patch b/main/musl/0016-rework-ldso-handling-of-global-symbol-table-for-cons.patch new file mode 100644 index 0000000000..03e1da813b --- /dev/null +++ b/main/musl/0016-rework-ldso-handling-of-global-symbol-table-for-cons.patch @@ -0,0 +1,255 @@ +From 4ff234f6cba96403b5de6d29d48a59fd73252040 Mon Sep 17 00:00:00 2001 +From: Rich Felker <dalias@aerifal.cx> +Date: Sun, 12 Mar 2017 21:03:05 -0400 +Subject: [PATCH] rework ldso handling of global symbol table for consistency + +when loading libraries with dlopen, the caller can request that the +library's symbols become part of the global symbol table, or that they +only be used for resolving relocations in the loaded library and its +dependencies. in the latter case, a subsequent dlopen of the same +library can upgrade it to global status. + +previously, if a library was upgraded from local to global mode, its +symbols entered the symbol lookup search order at the point where the +library was originally loaded. this means that a new call to dlopen +could change the value of a symbol that already had a visible +definition, an inconsistency which applications could observe. + +POSIX is unclear whether this should happen or whether it's permitted +to happen, but the resolution of Austin Group issue #982 made it +formally unspecified. + +with this patch, a library whose mode is upgraded from local to global +enters the symbol lookup order at the point where it was made global, +so that symbol resolution before and after the upgrade are consistent. + +in order to implement this change, the per-dso global flag is replaced +with a separate set of linked-list pointers for participation in the +global symbol table. this permits the order of dso objects for symbol +resolution to differ from the order used for iteration of all loaded +libraries. it also improves performance of find_sym, by avoiding a +branch per iteration and skipping, and especially in the case where +many non-global libraries have been loaded, by allowing the loop to +skip over them entirely. logic for temporarily adding non-global +libraries to the symbol table for relocation purposes is also mildly +simplified. +--- + ldso/dynlink.c | 97 ++++++++++++++++++++++++++++++++-------------------------- + 1 file 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(); +-- +2.12.1 + |