mailing list of musl libc
 help / color / mirror / code / Atom feed
* [PATCH] emulate lazy binding
@ 2017-03-13 23:47 Rich Felker
  2017-03-14  1:20 ` Khem Raj
  2017-03-14 18:14 ` Rich Felker
  0 siblings, 2 replies; 3+ messages in thread
From: Rich Felker @ 2017-03-13 23:47 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 286 bytes --]

Posting this to the list for any additional comments before I commit
it. I've done basic testing, and X.org server starts successfully on
Alpine with the 20-modules.conf file (Alpine's hard-coded xorg module
loading in dependency order) removed. Other smoke testing also passed.

Rich


[-- Attachment #2: 0001-emulate-lazy-relocation-as-deferrable-relocation.patch --]
[-- Type: text/plain, Size: 5993 bytes --]

From 0598d537a5a2045e3e14132fde2f2eaa62c12404 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Mon, 13 Mar 2017 08:52:41 -0400
Subject: [PATCH] emulate lazy relocation as deferrable relocation

traditional lazy relocation with call-time plt resolver is
intentionally not implemented, as it is a huge bug surface and demands
significant amounts of arch-specific code and requires ongoing
maintenance to ensure compatibility with applications which make use
of new additions to the arch's register file in passing function
arguments.

some applications, however, depend on the ability to dlopen modules
which have unsatisfied symbol references at the time they are loaded,
either avoiding use of the affected interfaces or manually loading
another module to provide the missing definition via their own module
dependency tracking outside the ELF data structures. while such usage
is non-conforming, failure to support it has been a significant
obstacle for users/distributions trying to support affected software,
particularly the X.org server.

instead of resolving lazy relocations at call time, this patch saves
unresolved GOT/PLT relocations for deferral and retries them after
each subsequent dlopen until they are resolved. since dlopen is the
only time at which the effective global symbol table can change, this
behavior is not observably different from traditional lazy binding,
and the required code is minimal.
---
 ldso/dynlink.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 66 insertions(+), 3 deletions(-)

diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 0bd9d50..144abf9 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -58,7 +58,8 @@ struct dso {
 	uint32_t *ghashtab;
 	int16_t *versym;
 	char *strings;
-	struct dso *syms_next;
+	struct dso *syms_next, *lazy_next;
+	size_t *lazy, lazy_cnt;
 	unsigned char *map;
 	size_t map_len;
 	dev_t dev;
@@ -113,7 +114,7 @@ static struct builtin_tls {
 static size_t *saved_addends, *apply_addends_to;
 
 static struct dso ldso;
-static struct dso *head, *tail, *fini_head, *syms_tail;
+static struct dso *head, *tail, *fini_head, *syms_tail, *lazy_head;
 static char *env_path, *sys_path;
 static unsigned long long gencnt;
 static int runtime;
@@ -350,6 +351,13 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 				: find_sym(ctx, name, type==REL_PLT);
 			if (!def.sym && (sym->st_shndx != SHN_UNDEF
 			    || sym->st_info>>4 != STB_WEAK)) {
+				if (dso->lazy && (type==REL_PLT || type==REL_GOT)) {
+					dso->lazy[3*dso->lazy_cnt+0] = rel[0];
+					dso->lazy[3*dso->lazy_cnt+1] = rel[1];
+					dso->lazy[3*dso->lazy_cnt+2] = addend;
+					dso->lazy_cnt++;
+					continue;
+				}
 				error("Error relocating %s: %s: symbol not found",
 					dso->name, name);
 				if (runtime) longjmp(*rtld_fail, 1);
@@ -451,6 +459,26 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 	}
 }
 
+static void redo_lazy_relocs()
+{
+	struct dso *p = lazy_head, *next;
+	lazy_head = 0;
+	for (; p; p=next) {
+		next = p->lazy_next;
+		size_t size = p->lazy_cnt*3*sizeof(size_t);
+		p->lazy_cnt = 0;
+		do_relocs(p, p->lazy, size, 3);
+		if (p->lazy_cnt) {
+			p->lazy_next = lazy_head;
+			lazy_head = p;
+		} else {
+			free(p->lazy);
+			p->lazy = 0;
+			p->lazy_next = 0;
+		}
+	}
+}
+
 /* A huge hack: to make up for the wastefulness of shared libraries
  * needing at least a page of dirty memory even if they have no global
  * data, we reclaim the gaps at the beginning and end of writable maps
@@ -1653,9 +1681,31 @@ _Noreturn void __dls3(size_t *sp)
 	for(;;);
 }
 
+static void prepare_lazy(struct dso *p)
+{
+	size_t dyn[DYN_CNT], n, flags1;
+	decode_vec(p->dynv, dyn, DYN_CNT);
+	search_vec(p->dynv, &flags1, DT_FLAGS_1);
+	if (dyn[DT_BIND_NOW] || (dyn[DT_FLAGS] & DF_BIND_NOW) || (flags1 & DF_1_NOW))
+		return;
+	n = dyn[DT_RELSZ]/2 + dyn[DT_RELASZ]/3 + dyn[DT_PLTRELSZ]/2 + 1;
+	if (NEED_MIPS_GOT_RELOCS) {
+		size_t j=0; search_vec(p->dynv, &j, DT_MIPS_GOTSYM);
+		size_t i=0; search_vec(p->dynv, &i, DT_MIPS_SYMTABNO);
+		n += i-j;
+	}
+	p->lazy = calloc(n, 3*sizeof(size_t));
+	if (!p->lazy) {
+		error("Error preparing lazy relocation for %s: %m", p->name);
+		longjmp(*rtld_fail, 1);
+	}
+	p->lazy_next = lazy_head;
+	lazy_head = p;
+}
+
 void *dlopen(const char *file, int mode)
 {
-	struct dso *volatile p, *orig_tail, *orig_syms_tail, *next;
+	struct dso *volatile p, *orig_tail, *orig_syms_tail, *orig_lazy_head, *next;
 	struct tls_module *orig_tls_tail;
 	size_t orig_tls_cnt, orig_tls_offset, orig_tls_align;
 	size_t i;
@@ -1673,6 +1723,7 @@ void *dlopen(const char *file, int mode)
 	orig_tls_cnt = tls_cnt;
 	orig_tls_offset = tls_offset;
 	orig_tls_align = tls_align;
+	orig_lazy_head = lazy_head;
 	orig_syms_tail = syms_tail;
 	orig_tail = tail;
 	noload = mode & RTLD_NOLOAD;
@@ -1701,6 +1752,7 @@ void *dlopen(const char *file, int mode)
 		tls_cnt = orig_tls_cnt;
 		tls_offset = orig_tls_offset;
 		tls_align = orig_tls_align;
+		lazy_head = orig_lazy_head;
 		tail = orig_tail;
 		tail->next = 0;
 		p = 0;
@@ -1718,6 +1770,12 @@ void *dlopen(const char *file, int mode)
 	/* First load handling */
 	if (!p->relocated) {
 		load_deps(p);
+		if ((mode & RTLD_LAZY)) {
+			prepare_lazy(p);
+			if (p->deps) for (i=0; p->deps[i]; i++)
+				if (!p->deps[i]->relocated)
+					prepare_lazy(p->deps[i]);
+		}
 		/* Make new symbols global, at least temporarily, so we can do
 		 * relocations. If not RTLD_GLOBAL, this is reverted below. */
 		add_syms(p);
@@ -1732,6 +1790,11 @@ void *dlopen(const char *file, int mode)
 	if (!(mode & RTLD_GLOBAL))
 		revert_syms(orig_syms_tail);
 
+	/* Processing of deferred lazy relocations must not happen until
+	 * the new libraries are committed; otherwise we could end up with
+	 * relocations resolved to symbol definitions that get removed. */
+	redo_lazy_relocs();
+
 	update_tls_size();
 	_dl_debug_state();
 	orig_tail = tail;
-- 
2.10.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] emulate lazy binding
  2017-03-13 23:47 [PATCH] emulate lazy binding Rich Felker
@ 2017-03-14  1:20 ` Khem Raj
  2017-03-14 18:14 ` Rich Felker
  1 sibling, 0 replies; 3+ messages in thread
From: Khem Raj @ 2017-03-14  1:20 UTC (permalink / raw)
  To: musl


[-- Attachment #1.1: Type: text/plain, Size: 635 bytes --]



On 3/13/17 4:47 PM, Rich Felker wrote:
> Posting this to the list for any additional comments before I commit
> it. I've done basic testing, and X.org server starts successfully on
> Alpine with the 20-modules.conf file (Alpine's hard-coded xorg module
> loading in dependency order) removed. Other smoke testing also passed.
> 

I have tested this patch with Yocto project as well and I can confirm
that it worked on Rpi3 to bring up X after removing module preloading

http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/meta/recipes-graphics/xorg-xserver/xserver-xf86-config/10-preload-modules.conf

> Rich
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 204 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] emulate lazy binding
  2017-03-13 23:47 [PATCH] emulate lazy binding Rich Felker
  2017-03-14  1:20 ` Khem Raj
@ 2017-03-14 18:14 ` Rich Felker
  1 sibling, 0 replies; 3+ messages in thread
From: Rich Felker @ 2017-03-14 18:14 UTC (permalink / raw)
  To: musl

On Mon, Mar 13, 2017 at 07:47:35PM -0400, Rich Felker wrote:
>  
> +static void prepare_lazy(struct dso *p)
> +{
> +	size_t dyn[DYN_CNT], n, flags1;
> +	decode_vec(p->dynv, dyn, DYN_CNT);
> +	search_vec(p->dynv, &flags1, DT_FLAGS_1);
> +	if (dyn[DT_BIND_NOW] || (dyn[DT_FLAGS] & DF_BIND_NOW) || (flags1 & DF_1_NOW))
> +		return;

One fix, flags1 should be initialized to 0 in case search_vec fails.

I'll go ahead and commit soon.

Rich


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-03-14 18:14 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-13 23:47 [PATCH] emulate lazy binding Rich Felker
2017-03-14  1:20 ` Khem Raj
2017-03-14 18:14 ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).