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.
This commit is contained in:
Rich Felker 2015-09-17 17:18:09 +00:00
parent 6fc30c2493
commit 301335a80b
1 changed files with 22 additions and 19 deletions

View File

@ -122,6 +122,9 @@ static int dl_strcmp(const char *l, const char *r)
} }
#define strcmp(l,r) dl_strcmp(l,r) #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) static void decode_vec(size_t *v, size_t *a, size_t cnt)
{ {
size_t i; size_t i;
@ -414,8 +417,8 @@ static void reclaim(struct dso *dso, size_t start, size_t end)
start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t); start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t);
end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t); end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t);
if (start>end || end-start < 4*sizeof(size_t)) return; if (start>end || end-start < 4*sizeof(size_t)) return;
a = (size_t *)(dso->base + start); a = laddr(dso, start);
z = (size_t *)(dso->base + end); z = laddr(dso, end);
a[-2] = 1; a[-2] = 1;
a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1; a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1;
z[1] = 1; z[1] = 1;
@ -687,18 +690,18 @@ static void decode_dyn(struct dso *p)
{ {
size_t dyn[DYN_CNT]; size_t dyn[DYN_CNT];
decode_vec(p->dynv, dyn, DYN_CNT); decode_vec(p->dynv, dyn, DYN_CNT);
p->syms = (void *)(p->base + dyn[DT_SYMTAB]); p->syms = laddr(p, dyn[DT_SYMTAB]);
p->strings = (void *)(p->base + dyn[DT_STRTAB]); p->strings = laddr(p, dyn[DT_STRTAB]);
if (dyn[0]&(1<<DT_HASH)) 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)) if (dyn[0]&(1<<DT_RPATH))
p->rpath_orig = (void *)(p->strings + dyn[DT_RPATH]); p->rpath_orig = (void *)(p->strings + dyn[DT_RPATH]);
if (dyn[0]&(1<<DT_RUNPATH)) if (dyn[0]&(1<<DT_RUNPATH))
p->rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]); p->rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]);
if (search_vec(p->dynv, dyn, DT_GNU_HASH)) 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)) 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) static struct dso *load_library(const char *name, struct dso *needed_by)
@ -980,7 +983,7 @@ static void kernel_mapped_dso(struct dso *p)
Phdr *ph = p->phdr; Phdr *ph = p->phdr;
for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) { for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) {
if (ph->p_type == PT_DYNAMIC) { 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) { } else if (ph->p_type == PT_GNU_RELRO) {
p->relro_start = ph->p_vaddr & -PAGE_SIZE; p->relro_start = ph->p_vaddr & -PAGE_SIZE;
p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE;
@ -1007,12 +1010,12 @@ static void do_fini()
decode_vec(p->dynv, dyn, DYN_CNT); decode_vec(p->dynv, dyn, DYN_CNT);
if (dyn[0] & (1<<DT_FINI_ARRAY)) { if (dyn[0] & (1<<DT_FINI_ARRAY)) {
size_t n = dyn[DT_FINI_ARRAYSZ]/sizeof(size_t); 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)(); while (n--) ((void (*)(void))*--fn)();
} }
#ifndef NO_LEGACY_INITFINI #ifndef NO_LEGACY_INITFINI
if ((dyn[0] & (1<<DT_FINI)) && dyn[DT_FINI]) if ((dyn[0] & (1<<DT_FINI)) && dyn[DT_FINI])
((void (*)(void))(p->base + dyn[DT_FINI]))(); ((void (*)(void))laddr(p, dyn[DT_FINI]))();
#endif #endif
} }
} }
@ -1035,11 +1038,11 @@ static void do_init_fini(struct dso *p)
} }
#ifndef NO_LEGACY_INITFINI #ifndef NO_LEGACY_INITFINI
if ((dyn[0] & (1<<DT_INIT)) && dyn[DT_INIT]) if ((dyn[0] & (1<<DT_INIT)) && dyn[DT_INIT])
((void (*)(void))(p->base + dyn[DT_INIT]))(); ((void (*)(void))laddr(p, dyn[DT_INIT]))();
#endif #endif
if (dyn[0] & (1<<DT_INIT_ARRAY)) { if (dyn[0] & (1<<DT_INIT_ARRAY)) {
size_t n = dyn[DT_INIT_ARRAYSZ]/sizeof(size_t); 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++)(); while (n--) ((void (*)(void))*fn++)();
} }
if (!need_locking && libc.threads_minus_1) { if (!need_locking && libc.threads_minus_1) {
@ -1276,8 +1279,8 @@ _Noreturn void __dls3(size_t *sp)
app.tls_align = phdr->p_align; app.tls_align = phdr->p_align;
} }
} }
if (app.tls_size) app.tls_image = (char *)app.base + tls_image; if (app.tls_size) app.tls_image = laddr(&app, tls_image);
if (interp_off) ldso.name = (char *)app.base + interp_off; if (interp_off) ldso.name = laddr(&app, interp_off);
if ((aux[0] & (1UL<<AT_EXECFN)) if ((aux[0] & (1UL<<AT_EXECFN))
&& strncmp((char *)aux[AT_EXECFN], "/proc/", 6)) && strncmp((char *)aux[AT_EXECFN], "/proc/", 6))
app.name = (char *)aux[AT_EXECFN]; app.name = (char *)aux[AT_EXECFN];
@ -1334,7 +1337,7 @@ _Noreturn void __dls3(size_t *sp)
close(fd); close(fd);
ldso.name = ldname; ldso.name = ldname;
app.name = argv[0]; 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 /* Find the name that would have been used for the dynamic
* linker had ldd not taken its place. */ * linker had ldd not taken its place. */
if (ldd_mode) { if (ldd_mode) {
@ -1571,7 +1574,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
if (!def.sym) goto failed; if (!def.sym) goto failed;
if ((def.sym->st_info&0xf) == STT_TLS) if ((def.sym->st_info&0xf) == STT_TLS)
return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value}); 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)) if (invalid_dso_handle(p))
return 0; return 0;
@ -1585,7 +1588,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
if (sym && (sym->st_info&0xf) == STT_TLS) if (sym && (sym->st_info&0xf) == STT_TLS)
return __tls_get_addr((size_t []){p->tls_id, sym->st_value}); return __tls_get_addr((size_t []){p->tls_id, sym->st_value});
if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) 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 (p->deps) for (i=0; p->deps[i]; i++) {
if ((ght = p->deps[i]->ghashtab)) { if ((ght = p->deps[i]->ghashtab)) {
if (!gh) gh = gnu_hash(s); if (!gh) gh = gnu_hash(s);
@ -1597,7 +1600,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra)
if (sym && (sym->st_info&0xf) == STT_TLS) if (sym && (sym->st_info&0xf) == STT_TLS)
return __tls_get_addr((size_t []){p->deps[i]->tls_id, sym->st_value}); 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)) 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: failed:
error("Symbol not found: %s", s); error("Symbol not found: %s", s);
@ -1645,7 +1648,7 @@ int __dladdr(const void *addr, Dl_info *info)
if (sym->st_value if (sym->st_value
&& (1<<(sym->st_info&0xf) & OK_TYPES) && (1<<(sym->st_info&0xf) & OK_TYPES)
&& (1<<(sym->st_info>>4) & OK_BINDS)) { && (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) if (symaddr > addr || symaddr < best)
continue; continue;
best = symaddr; best = symaddr;