begin refactoring load address computations in dynamic linker

for ordinary ELF with fixed segment displacements, load address
computation is simply adding the base load address. but for FDPIC,
each segment has its own load address, and virtual addresses need to
be adjusted according to the segment they fall in. abstracting this
computation is the first step to making the dynamic linker ready for
FDPIC.

for this first commit, a macro is used rather than a function in order
to facilitate correctness checking. I have verified that the generated
code does not change on my i386 build.
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 70b2ae1..75fae76 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -122,6 +122,9 @@
 }
 #define strcmp(l,r) dl_strcmp(l,r)
 
+/* Compute load address for a virtual address in a given dso. */
+#define laddr(p, v) (void *)((p)->base + (v))
+
 static void decode_vec(size_t *v, size_t *a, size_t cnt)
 {
 	size_t i;
@@ -414,8 +417,8 @@
 	start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t);
 	end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t);
 	if (start>end || end-start < 4*sizeof(size_t)) return;
-	a = (size_t *)(dso->base + start);
-	z = (size_t *)(dso->base + end);
+	a = laddr(dso, start);
+	z = laddr(dso, end);
 	a[-2] = 1;
 	a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1;
 	z[1] = 1;
@@ -687,18 +690,18 @@
 {
 	size_t dyn[DYN_CNT];
 	decode_vec(p->dynv, dyn, DYN_CNT);
-	p->syms = (void *)(p->base + dyn[DT_SYMTAB]);
-	p->strings = (void *)(p->base + dyn[DT_STRTAB]);
+	p->syms = laddr(p, dyn[DT_SYMTAB]);
+	p->strings = laddr(p, dyn[DT_STRTAB]);
 	if (dyn[0]&(1<<DT_HASH))
-		p->hashtab = (void *)(p->base + dyn[DT_HASH]);
+		p->hashtab = laddr(p, dyn[DT_HASH]);
 	if (dyn[0]&(1<<DT_RPATH))
 		p->rpath_orig = (void *)(p->strings + dyn[DT_RPATH]);
 	if (dyn[0]&(1<<DT_RUNPATH))
 		p->rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]);
 	if (search_vec(p->dynv, dyn, DT_GNU_HASH))
-		p->ghashtab = (void *)(p->base + *dyn);
+		p->ghashtab = laddr(p, *dyn);
 	if (search_vec(p->dynv, dyn, DT_VERSYM))
-		p->versym = (void *)(p->base + *dyn);
+		p->versym = laddr(p, *dyn);
 }
 
 static struct dso *load_library(const char *name, struct dso *needed_by)
@@ -980,7 +983,7 @@
 	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);
+			p->dynv = laddr(p, 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;
@@ -1007,12 +1010,12 @@
 		decode_vec(p->dynv, dyn, DYN_CNT);
 		if (dyn[0] & (1<<DT_FINI_ARRAY)) {
 			size_t n = dyn[DT_FINI_ARRAYSZ]/sizeof(size_t);
-			size_t *fn = (size_t *)(p->base + dyn[DT_FINI_ARRAY])+n;
+			size_t *fn = (size_t *)laddr(p, dyn[DT_FINI_ARRAY])+n;
 			while (n--) ((void (*)(void))*--fn)();
 		}
 #ifndef NO_LEGACY_INITFINI
 		if ((dyn[0] & (1<<DT_FINI)) && dyn[DT_FINI])
-			((void (*)(void))(p->base + dyn[DT_FINI]))();
+			((void (*)(void))laddr(p, dyn[DT_FINI]))();
 #endif
 	}
 }
@@ -1035,11 +1038,11 @@
 		}
 #ifndef NO_LEGACY_INITFINI
 		if ((dyn[0] & (1<<DT_INIT)) && dyn[DT_INIT])
-			((void (*)(void))(p->base + dyn[DT_INIT]))();
+			((void (*)(void))laddr(p, dyn[DT_INIT]))();
 #endif
 		if (dyn[0] & (1<<DT_INIT_ARRAY)) {
 			size_t n = dyn[DT_INIT_ARRAYSZ]/sizeof(size_t);
-			size_t *fn = (void *)(p->base + dyn[DT_INIT_ARRAY]);
+			size_t *fn = laddr(p, dyn[DT_INIT_ARRAY]);
 			while (n--) ((void (*)(void))*fn++)();
 		}
 		if (!need_locking && libc.threads_minus_1) {
@@ -1276,8 +1279,8 @@
 				app.tls_align = phdr->p_align;
 			}
 		}
-		if (app.tls_size) app.tls_image = (char *)app.base + tls_image;
-		if (interp_off) ldso.name = (char *)app.base + interp_off;
+		if (app.tls_size) app.tls_image = laddr(&app, tls_image);
+		if (interp_off) ldso.name = laddr(&app, interp_off);
 		if ((aux[0] & (1UL<<AT_EXECFN))
 		    && strncmp((char *)aux[AT_EXECFN], "/proc/", 6))
 			app.name = (char *)aux[AT_EXECFN];
@@ -1334,7 +1337,7 @@
 		close(fd);
 		ldso.name = ldname;
 		app.name = argv[0];
-		aux[AT_ENTRY] = (size_t)app.base + ehdr->e_entry;
+		aux[AT_ENTRY] = (size_t)laddr(&app, ehdr->e_entry);
 		/* Find the name that would have been used for the dynamic
 		 * linker had ldd not taken its place. */
 		if (ldd_mode) {
@@ -1571,7 +1574,7 @@
 		if (!def.sym) goto failed;
 		if ((def.sym->st_info&0xf) == STT_TLS)
 			return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value});
-		return def.dso->base + def.sym->st_value;
+		return laddr(def.dso, def.sym->st_value);
 	}
 	if (invalid_dso_handle(p))
 		return 0;
@@ -1585,7 +1588,7 @@
 	if (sym && (sym->st_info&0xf) == STT_TLS)
 		return __tls_get_addr((size_t []){p->tls_id, sym->st_value});
 	if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
-		return p->base + sym->st_value;
+		return laddr(p, sym->st_value);
 	if (p->deps) for (i=0; p->deps[i]; i++) {
 		if ((ght = p->deps[i]->ghashtab)) {
 			if (!gh) gh = gnu_hash(s);
@@ -1597,7 +1600,7 @@
 		if (sym && (sym->st_info&0xf) == STT_TLS)
 			return __tls_get_addr((size_t []){p->deps[i]->tls_id, sym->st_value});
 		if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
-			return p->deps[i]->base + sym->st_value;
+			return laddr(p->deps[i], sym->st_value);
 	}
 failed:
 	error("Symbol not found: %s", s);
@@ -1645,7 +1648,7 @@
 		if (sym->st_value
 		 && (1<<(sym->st_info&0xf) & OK_TYPES)
 		 && (1<<(sym->st_info>>4) & OK_BINDS)) {
-			void *symaddr = p->base + sym->st_value;
+			void *symaddr = laddr(p, sym->st_value);
 			if (symaddr > addr || symaddr < best)
 				continue;
 			best = symaddr;