exec, mmap, musl: dynamic linking
A program that names an interpreter in PT_INTERP gets it loaded too, at the bottom of the mmap area, and started instead -- with AT_PHDR, AT_PHENT, AT_PHNUM, AT_BASE and AT_ENTRY to find the program by. ET_DYN images are placed at a base: the interpreter there, a PIE program where a fixed one would go. Static musl programs get AT_PHDR now as well, which is how musl finds their TLS template. mmap(MAP_FIXED) of a file handed back zeroed pages whatever the descriptor said, and kept no record of them, so fork() did not copy them. A dynamic linker maps every library segment after the first that way. Fixed mappings now read the file and are recorded wherever no mapping already covers them. musl is built shared as well as static, and libc.so ships as /lib/ld-musl-x86_64.so.1 -- libc and loader in one file. Every port still links -static on purpose. cmd/dynhello is the test: against libc.so and a library of its own, checking TLS, the heap, and a fork whose child still has both. mprotect is accepted and not enforced yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
6bfb367090
commit
43305768cb
6 changed files with 328 additions and 35 deletions
|
|
@ -76,6 +76,41 @@ vma_note_anon(struct proc *p, uint64 va, uint64 len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Record [va, va+len) as anonymous memory wherever no mapping already covers
|
||||
// it, for a MAP_FIXED that may land anywhere: inside an earlier mapping, across
|
||||
// the end of one, or in a gap. Below sz is the program image and its heap,
|
||||
// which fork copies as [0, sz) and needs no record -- a second one there would
|
||||
// have fork map those pages twice.
|
||||
static int
|
||||
vma_cover_anon(struct proc *p, uint64 va, uint64 len)
|
||||
{
|
||||
uint64 cur = va, end = va + len;
|
||||
|
||||
if (cur < PGROUNDUP(p->sz))
|
||||
cur = PGROUNDUP(p->sz);
|
||||
while (cur < end) {
|
||||
uint64 next = end;
|
||||
int inside = -1;
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
if (!v->used)
|
||||
continue;
|
||||
if (v->addr <= cur && cur < v->addr + v->length)
|
||||
inside = i;
|
||||
else if (v->addr > cur && v->addr < next)
|
||||
next = v->addr;
|
||||
}
|
||||
if (inside >= 0) {
|
||||
cur = p->vma[inside].addr + p->vma[inside].length;
|
||||
continue;
|
||||
}
|
||||
if (vma_note_anon(p, cur, next - cur) < 0)
|
||||
return -ENOMEM;
|
||||
cur = next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_sbrk(void)
|
||||
{
|
||||
|
|
@ -127,11 +162,34 @@ sys_mmap(void)
|
|||
return va;
|
||||
for (uint64 a = va; a < va + length; a += PGSIZE) {
|
||||
char *mem = kalloc();
|
||||
if (!mem) return -1;
|
||||
if (!mem) return -ENOMEM;
|
||||
memset(mem, 0, PGSIZE);
|
||||
if (mappages(myproc()->pgdir, (void*)a, PGSIZE, V2P((uint64)mem), PTE_W | PTE_U) < 0)
|
||||
return -1;
|
||||
if (mappages(myproc()->pgdir, (void*)a, PGSIZE, V2P((uint64)mem), PTE_W | PTE_U) < 0) {
|
||||
kfree(mem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
// The file, when there is one. This path used to ignore it and hand
|
||||
// back zeroed pages whatever fd said -- and a dynamic linker maps
|
||||
// every segment of every library after the first exactly this way,
|
||||
// MAP_FIXED at an offset into the file, so libc came up as a library
|
||||
// of zeros. A private copy, as in the non-fixed path below.
|
||||
if (f && f->type == FD_INODE && f->ip->type != T_DEV &&
|
||||
!(flags & MAP_ANONYMOUS)) {
|
||||
if ((flags & MAP_SHARED) && (prot & PROT_WRITE))
|
||||
return -ENODEV;
|
||||
if (!f->readable)
|
||||
return -EACCES;
|
||||
ilock(f->ip);
|
||||
readi(f->ip, 0, va, offset, length);
|
||||
iunlock(f->ip);
|
||||
}
|
||||
|
||||
// And remembered. Without a record fork() did not copy these pages,
|
||||
// so a child of a dynamically linked program had no libc.
|
||||
if (vma_cover_anon(myproc(), va, length) < 0)
|
||||
return -ENOMEM;
|
||||
return va;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue