about summary refs log tree commit diff
path: root/src/ldso/dynlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ldso/dynlink.c')
-rw-r--r--src/ldso/dynlink.c51
1 files changed, 23 insertions, 28 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index de0f2ac8..2f151c22 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -56,6 +56,7 @@ struct dso {
 
 	Phdr *phdr;
 	int phnum;
+	size_t phentsize;
 	int refcnt;
 	Sym *syms;
 	uint32_t *hashtab;
@@ -298,9 +299,12 @@ static void reclaim(struct dso *dso, size_t start, size_t end)
 	free(a);
 }
 
-static void reclaim_gaps(struct dso *dso, Phdr *ph, size_t phent, size_t phcnt)
+static void reclaim_gaps(struct dso *dso)
 {
-	for (; phcnt--; ph=(void *)((char *)ph+phent)) {
+	Phdr *ph;
+	size_t phcnt;
+
+	for (phcnt = dso->phnum, ph = dso->phdr; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) {
 		if (ph->p_type!=PT_LOAD) continue;
 		if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue;
 		reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr);
@@ -400,6 +404,7 @@ static void *map_library(int fd, struct dso *dso)
 			dso->phdr = (void *)(base + ph->p_vaddr
 				+ (eh->e_phoff-ph->p_offset));
 			dso->phnum = eh->e_phnum;
+			dso->phentsize = eh->e_phentsize;
 		}
 		/* Reuse the existing mapping for the lowest-address LOAD */
 		if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue;
@@ -430,7 +435,7 @@ static void *map_library(int fd, struct dso *dso)
 	dso->base = base;
 	dso->dynv = (void *)(base+dyn);
 	if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);
-	if (!runtime) reclaim_gaps(dso, ph0, eh->e_phentsize, eh->e_phnum);
+	if (!runtime) reclaim_gaps(dso);
 	free(allocated_buf);
 	return map;
 noexec:
@@ -787,19 +792,14 @@ static void reloc_all(struct dso *p)
 	}
 }
 
-static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride)
-{
-	for (; cnt--; ph = (void *)((char *)ph + stride))
-		if (ph->p_type == PT_DYNAMIC)
-			return ph->p_vaddr;
-	return 0;
-}
-
-static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p)
+static void kernel_mapped_dso(struct dso *p)
 {
-	size_t min_addr = -1, max_addr = 0;
-	for (; cnt--; ph = (void *)((char *)ph + stride)) {
-		if (ph->p_type == PT_GNU_RELRO) {
+	size_t min_addr = -1, max_addr = 0, cnt;
+	Phdr *ph = p->phdr;
+	for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) {
+		if (ph->p_type == PT_DYNAMIC) {
+			p->dynv = (void *)(p->base + ph->p_vaddr);
+		} else if (ph->p_type == PT_GNU_RELRO) {
 			p->relro_start = ph->p_vaddr & -PAGE_SIZE;
 			p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE;
 		}
@@ -813,6 +813,7 @@ static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p)
 	max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE;
 	p->map = p->base + min_addr;
 	p->map_len = max_addr - min_addr;
+	p->kernel_mapped = 1;
 }
 
 static void do_fini()
@@ -1023,13 +1024,11 @@ void *__dynlink(int argc, char **argv)
 	lib->base = (void *)aux[AT_BASE];
 	lib->name = lib->shortname = "libc.so";
 	lib->global = 1;
-	lib->kernel_mapped = 1;
 	ehdr = (void *)lib->base;
 	lib->phnum = ehdr->e_phnum;
 	lib->phdr = (void *)(aux[AT_BASE]+ehdr->e_phoff);
-	find_map_range(lib->phdr, ehdr->e_phnum, ehdr->e_phentsize, lib);
-	lib->dynv = (void *)(lib->base + find_dyn(lib->phdr,
-		ehdr->e_phnum, ehdr->e_phentsize));
+	lib->phentsize = ehdr->e_phentsize;
+	kernel_mapped_dso(lib);
 	decode_dyn(lib);
 
 	if (aux[AT_PHDR]) {
@@ -1038,6 +1037,7 @@ void *__dynlink(int argc, char **argv)
 		/* Find load address of the main program, via AT_PHDR vs PT_PHDR. */
 		app->phdr = phdr = (void *)aux[AT_PHDR];
 		app->phnum = aux[AT_PHNUM];
+		app->phentsize = aux[AT_PHENT];
 		for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
 			if (phdr->p_type == PT_PHDR)
 				app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);
@@ -1057,11 +1057,7 @@ void *__dynlink(int argc, char **argv)
 			app->name = (char *)aux[AT_EXECFN];
 		else
 			app->name = argv[0];
-		app->kernel_mapped = 1;
-		app->dynv = (void *)(app->base + find_dyn(
-			(void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
-		find_map_range((void *)aux[AT_PHDR],
-			aux[AT_PHNUM], aux[AT_PHENT], app);
+		kernel_mapped_dso(app);
 	} else {
 		int fd;
 		char *ldname = argv[0];
@@ -1127,6 +1123,7 @@ void *__dynlink(int argc, char **argv)
 		ehdr = (void *)vdso_base;
 		vdso->phdr = phdr = (void *)(vdso_base + ehdr->e_phoff);
 		vdso->phnum = ehdr->e_phnum;
+		vdso->phentsize = ehdr->e_phentsize;
 		for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
 			if (phdr->p_type == PT_DYNAMIC)
 				vdso->dynv = (void *)(vdso_base + phdr->p_offset);
@@ -1154,10 +1151,8 @@ void *__dynlink(int argc, char **argv)
 	/* PAST THIS POINT, ALL LIBC INTERFACES ARE FULLY USABLE. */
 
 	/* Donate unused parts of app and library mapping to malloc */
-	reclaim_gaps(app, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]);
-	ehdr = (void *)lib->base;
-	reclaim_gaps(lib, (void *)(lib->base+ehdr->e_phoff),
-		ehdr->e_phentsize, ehdr->e_phnum);
+	reclaim_gaps(app);
+	reclaim_gaps(lib);
 
 	/* Load preload/needed libraries, add their symbols to the global
 	 * namespace, and perform all remaining relocations. The main