lab8
用户栈参数
uint32_t argv_size=0;
uint32_t i;
//计算所有参数的长度总和
for (i = 0; i < argc; i ++) {
argv_size += strnlen(kargv[i],EXEC_MAX_ARG_LEN + 1)+1;
}
//在栈顶为字符串预留空间
uintptr_t stacktop = USTACKTOP - (argv_size/sizeof(long)+1)*sizeof(long);
//计算存放参数指针的数组地址
char** uargv=(char **)(stacktop - argc * sizeof(char *));
argv_size = 0;
for (i = 0; i < argc; i ++) {
//拷贝各字符串 并在指针数组记录字符串地址
uargv[i] = strcpy((char *)(stacktop + argv_size ), kargv[i]);
argv_size += strnlen(kargv[i],EXEC_MAX_ARG_LEN + 1)+1;
}
//在栈顶存放参数数量argc
stacktop = (uintptr_t)uargv - sizeof(int);
*(int *)stacktop = argc;
文件方法读入程序elf
//elf header 缓冲区
struct elfhdr elf;
//各program header 的缓冲区
struct proghdr ph;
//读入elf header 在文件的初始位置
load_icode_read(fd, &elf, sizeof(struct elfhdr), 0);
uint32_t vm_flags = 0, perm = PTE_U;
struct Page * page = NULL;
uintptr_t start, end, la;
uint32_t i;
//遍历program header数组
for (i = 0; i < elf.e_phnum; i++)
{
//读入program header i
load_icode_read(fd, &ph, sizeof(struct proghdr), elf.e_phoff + i * sizeof(struct proghdr));
if (ph.p_flags & ELF_PF_X) vm_flags |= VM_EXEC;
if (ph.p_flags & ELF_PF_W) vm_flags |= VM_WRITE;
if (ph.p_flags & ELF_PF_R) vm_flags |= VM_READ;
if (vm_flags & VM_WRITE) perm |= PTE_W;
start = ph.p_va;
end = start + ph.p_filesz;
//使用la作为每一页的虚拟地址 la保证为整数倍页大小
la = ROUNDDOWN(start, PGSIZE);
//为当前的段设置虚拟地址空间的连续地址 vma
mm_map(mm, ph.p_va, ph.p_filesz, vm_flags, NULL);
//作为从文件读入的缓冲 每次读入最多一页
void* buf = kmalloc(PGSIZE);
//记录每次读取时相对文件的偏移
uint32_t cur = ph.p_offset;
uint32_t offset, sz;
//start记录每次读取时虚拟地址空间的首地址
while (start < end)
{
//在内存中分配一页 并建立地址映射
page = pgdir_alloc_page(mm->pgdir, la, perm);
offset = start - la;
//sz记录每次读取的字节数
if (end >= la + PGSIZE)
{
sz = PGSIZE - offset;
}
else
sz = end - start;
//读取并拷贝
load_icode_read(fd, offset + buf, sz, cur);
memcpy(page2kva(page) + offset, offset + buf, sz);
la += PGSIZE;
start += sz;
cur += sz;
}
//判断是否存在bss段
//bss段不存储于elf 一下条件成立时需要在之前创建的段后面建立bss段 大小是两者差值
if (ph.p_memsz != ph.p_filesz)
{
//取bss段的尾地址
end = ph.p_va + ph.p_memsz;
offset = start - la + PGSIZE;
if (end >= la)
{
//之前创建的页中的bss段部分清零
sz = PGSIZE - offset;
memset(page2kva(page) + offset, 0, sz);
}
else
{
//如果bss段只占之前创建页的后面部分
sz = end - start;
memset(page2kva(page) + offset, 0, sz);
continue;
}
start += sz;
//后续需要为bss段申请page
while (start < end)
{
page = pgdir_alloc_page(mm->pgdir, la, perm);
if (end >= la + PGSIZE)
sz = PGSIZE;
else
sz = end - la;
memset(page2kva(page), 0, sz);
start += sz;
la += PGSIZE;
}
}
}