diff options
| -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(); | 
