From d610c148554766f2a0e48304fe2550b340f84872 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Tue, 17 Apr 2018 15:55:18 -0400 Subject: enable reclaim_gaps for fdpic the existing laddr function for fdpic cannot translate ELF virtual addresses outside of the LOAD segments to runtime addresses because the fdpic loadmap only covers the logically-mapped part. however the whole point of reclaim_gaps is to recover the slack space up to the page boundaries, so it needs to work with such addresses. add a new laddr_pg function that accepts any address in the page range for the LOAD segment by expanding the loadmap records out to page boundaries. only use the new version for reclaim_gaps, so as not to impact performance of other address lookups. also, only use laddr_pg for the start address of a gap; the end address lies one byte beyond the end, potentially in a different page where it would get mapped differently. instead of mapping end, apply the length (end-start) to the mapped value of start. --- ldso/dynlink.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'ldso/dynlink.c') diff --git a/ldso/dynlink.c b/ldso/dynlink.c index b9ff41bc..63e7b81f 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -158,10 +158,26 @@ static void *laddr(const struct dso *p, size_t v) for (j=0; v-p->loadmap->segs[j].p_vaddr >= p->loadmap->segs[j].p_memsz; j++); return (void *)(v - p->loadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); } +static void *laddr_pg(const struct dso *p, size_t v) +{ + size_t j=0; + size_t pgsz = PAGE_SIZE; + if (!p->loadmap) return p->base + v; + for (j=0; ; j++) { + size_t a = p->loadmap->segs[j].p_vaddr; + size_t b = a + p->loadmap->segs[j].p_memsz; + a &= -pgsz; + b += pgsz-1; + b &= -pgsz; + if (v-aloadmap->segs[j].p_vaddr + p->loadmap->segs[j].addr); +} #define fpaddr(p, v) ((void (*)())&(struct funcdesc){ \ laddr(p, v), (p)->got }) #else #define laddr(p, v) (void *)((p)->base + (v)) +#define laddr_pg(p, v) laddr(p, v) #define fpaddr(p, v) ((void (*)())laddr(p, v)) #endif @@ -484,7 +500,8 @@ static void reclaim(struct dso *dso, size_t start, size_t end) if (start >= dso->relro_start && start < dso->relro_end) start = dso->relro_end; if (end >= dso->relro_start && end < dso->relro_end) end = dso->relro_start; if (start >= end) return; - __malloc_donate(laddr(dso, start), laddr(dso, end)); + char *base = laddr_pg(dso, start); + __malloc_donate(base, base+(end-start)); } static void reclaim_gaps(struct dso *dso) @@ -492,7 +509,6 @@ static void reclaim_gaps(struct dso *dso) Phdr *ph = dso->phdr; size_t phcnt = dso->phnum; - if (DL_FDPIC) return; // FIXME for (; 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; -- cgit v1.2.1