summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
Diffstat (limited to 'ldso')
-rw-r--r--ldso/dynlink.c97
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();