提交 49ba38fa 创建 作者: Austin Clements's avatar Austin Clements

Map ELF segments with zeroed regions as two vmnodes

Previously, we mapped it as one node that spanned all of the pages, but had a smaller size. This causes a panic when we fault on pages beyond the size because vmnode::loadpg calls readi with a too-large offset. We could "fix" loadpg, but what we have now is actually POSIX-ish behavior (which says faults beyond the end of the mapped object should signal SIGBUS), so instead we fix the ELF loader to create two vmnodes in this situation. This gets usertests running again for me (it now fails at the BSS test, but at least it starts).
上级 a6d82a6c
......@@ -62,18 +62,40 @@ dosegment(inode* ip, vmap* vmp, u64 off)
return -1;
uptr va_start = PGROUNDDOWN(ph.vaddr);
uptr backed_end = PGROUNDUP(ph.vaddr + ph.filesz);
uptr va_end = PGROUNDUP(ph.vaddr + ph.memsz);
off_t in_off = ph.offset - PGOFFSET(ph.vaddr);
size_t in_sz = ph.filesz + PGOFFSET(ph.vaddr);
size_t npg = (va_end - va_start) / PGSIZE;
vmnode* node = new vmnode(npg, ONDEMAND, ip, in_off, in_sz);
if (node == nullptr)
return -1;
if (va_start != backed_end) {
// Part represented in the file. This may be empty, which is why
// this code is conditional.
size_t npg = (backed_end - va_start) / PGSIZE;
vmnode* node = new vmnode(npg, ONDEMAND, ip, in_off, in_sz);
if (node == nullptr)
return -1;
if (vmp->insert(node, va_start, 1) < 0) {
delete node;
return -1;
if (vmp->insert(node, va_start, 1) < 0) {
delete node;
return -1;
}
}
if (va_end != backed_end) {
// Zeroed part omitted from the file. This must be mapped
// separately both to avoid mapping non-zero data that follows
// this segment in the file and so the size of the vmnode doesn't
// exceed the size of the file (which could cause a failure on
// page fault).
size_t npg = (va_end - backed_end) / PGSIZE;
vmnode* node = new vmnode(npg);
if (node == nullptr)
return -1;
if (vmp->insert(node, backed_end, 1) < 0) {
delete node;
return -1;
}
}
return 0;
......
......@@ -595,6 +595,8 @@ vmap::pagefault(uptr va, u32 err)
// XXX(sbw) you might think we don't need to zero if ONDEMAND;
// however, our vmnode might include not backed by a file
// (e.g. the bss section of an ELF segment)
// XXX(austin) Why is this still necessary now that we map zeroed
// parts of segments separately?
if (m->n->allocpg(npg, true) < 0)
throw_bad_alloc();
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论