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;
            }



        }

    }


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值