《ucore lab8》实验报告
资源
练习1: 完成读文件操作的实现(需要编码)
题目
首先了解打开文件的处理流程,然后参考本实验后续的文件读写操作的过程分析,编写在sfs_inode.c中sfs_io_nolock读文件中数据的实现代码。
请在实验报告中给出设计实现“UNIX的PIPE机制”的概要设计方案,鼓励给出详细设计方案。
解答
了解打开文件的处理流程
已对打开文件的代码流程进行了详细分析,见lab8 源码分析:用户执行open的详细流程
实现sfs_io_nolock读文件数据的功能
根据提示不难完成编码。原代码中提供两个接口sfs_rbuf和sfs_rblock,分别用于以字节和文件块(实际上就是页面大小)为单位来读取文件。主要需要考虑到读文件时的起始和结束位置可能没与block起始位置对齐,对于不足一个block的部分调用sfs_rbuf来读取内容,对于中间多个block的部分则调用sfs_rblock来读取。
设计实现“UNIX的PIPE机制”(待完成)
练习2: 完成基于文件系统的执行程序机制的实现(需要编码)
题目
改写proc.c中的load_icode函数和其他相关函数,实现基于文件系统的执行程序机制。执行:make qemu。如果能看看到sh用户程序的执行界面,则基本成功了。如果在sh用户界面上可以执行“ls”、“hello”等其他放置在sfs文件系统中的其他执行程序,则可以认为本实验基本成功。
请在实验报告中给出设计实现基于“UNIX的硬链接和软链接机制”的概要设计方案,鼓励给出详细设计方案。
解答
实现基于文件系统的执行程序机制
首先要获取ELF文件的大小len,方法是:使用fd索引fd_array,得到对应的file,根据file->inode->sfs_inode->sfs_disk_inode->size得到ELF文件大小。
然后申请大小为len的缓冲区buf,接下来调用load_icode_read来读取ELF文件的内容并复制到buf,接下来解析ELF文件内容并复制相应section,这部分操作与之前的实验相同。
接下来还需要拷贝输入参数argc和kargv到用户栈顶,并根据输入参数所占的内存大小修改tf_esp的值。这样当程序沿着load_icode -> do_execve -> sys_exec -> syscall -> trap_dispatch -> trap -> trapret一路返回并执行iret时,就能从栈顶上面的几个位置获取到argc和argv的值。
设计实现基于“UNIX的硬链接和软链接机制”(待完成)
Bug 1:运行用户程序sh时内存访问异常
问题描述
编码完成后,执行sudo make qemu
,查看输出日志,发现没有进入sh界面,提示错误信息:“not valid addr b0000000, and can not find it in vma”。
定位流程
首先确认0xb0000000这个地址是何时被访问的。印象中这是用户栈顶的地址,查看load_icode的实现,果然发现在结尾处把tf_esp设置为USTACKTOP 0xb0000000,后面沿着do_execve -> sys_exec -> syscall -> trap_dispatch -> trap -> trapret一路返回,在trapret的结尾处执行iret,由于发生特权级转换,这时会把esp寄存器设置为0xb0000000.使用gdb调试发现,在进入用户程序的开头,会访问esp所指的内存,这时就发生缺页异常。
分析可能的原因:
- USTACKTOP这个地址本来就不能访问?
- 内核态到用户态的切换不成功?
- 页目录表和页表设置有误?
- 用户程序sh有问题?
- 用户程序的输入参数没设置?
使用gdb调试,在执行iret的地方使用si逐步调试,发现执行iret后,首先跳到地址为0x008004e9的位置运行,打开sh.asm查看对应位置的汇编代码,发现0x008004e9是start的起始位置,start的第二条指令
movl (%esp), ebx
会访问到0xb0000000,目的是加载argc参数。那么原因大概确定了,应该是我在load_icode函数中没设置好输入参数,导致现在访问输入参数失败。
_start:
# set ebp for backtrace
movl $0x0, %ebp
8004e9: bd 00 00 00 00 mov $0x0,%ebp
# load argc and argv
movl (%esp), %ebx
8004ee: 8b 1c 24 mov (%esp),%ebx
lea 0x4(%esp), %ecx
8004f1: 8d 4c 24 04 lea 0x4(%esp),%ecx
# move down the esp register since it may cause page fault in backtrace
subl $0x20, %esp
8004f5: 83 ec 20 sub $0x20,%esp
# save argc and argv on stack
pushl %ecx
8004f8: 51 push %ecx
pushl %ebx
8004f9: 53 push %ebx
# call user-program function
call umain
8004fa: e8 9d 04 00 00 call 80099c <umain>
- 那么为什么lab7不会有问题呢?于是回头看lab7的代码,首先查看lab7用户程序的start的汇编代码,发现果然有区别:lab8需要加载argc和argv,lab7则不需要加载。为什么会有这个差别?
_start:
# set ebp for backtrace
movl $0x0, %ebp
8003fb: bd 00 00 00 00 mov $0x0,%ebp
# move down the esp register
# since it may cause page fault in backtrace
subl $0x20, %esp
800400: 83 ec 20 sub $0x20,%esp
# call user-program function
call umain
800403: e8 f9 00 00 00 call 800501 <umain>
- 查看两个lab的umain的实现,终于找到原因:lab8的umain函数定义含有argc和argv两个输入参数,lab7的umain函数定义无输入参数。
// lab8
void umain(int argc, char *argv[]) {
int fd;
if ((fd = initfd(0, "stdin:", O_RDONLY)) < 0) {
warn("open <stdin> failed: %e.\n", fd);
}
if ((fd = initfd(1, "stdout:", O_WRONLY)) < 0) {
warn("open <stdout> failed: %e.\n", fd);
}
int ret = main(argc, argv);
exit(ret);
}
// lab7
void umain(void) {
int ret = main();
exit(ret);
}
但还是有疑问:即使我没在栈顶设置好argc和argv,也应该能访问栈顶吧?只是说访问到的数据是不确定的而已啊。会不会是0xb0000000刚好是禁止访问的边界地址?我试着将0xb0000000 - 16赋值给tf_esp,再运行,竟然不报错了!这时可以进入sh界面,输入ls没反应,输入hello或forktest等命令则正常运行。总之,这基本证明了我的猜想是正确的。
接下来不难得到正确解法:0xb0000000是用户地址边界,如果要存储argc和argv,则需要减去相应的值,在0xb0000000的前面来存储。修改后再运行,果然能正常进入sh界面,而且执行ls也能正常输出了。
最后的疑问:步骤6只是避免了访问地址边界,但没有正确设置argc和argv(使用gdb调试时发现此时argc和argv都设置为0了),为什么大部分命令也能正常运行,唯独ls运行异常(无输出)?查看ls.c文件,发现当输入argc为0时,确实不会执行任何操作;argc为1时,则会执行
ls .
.
《ucore lab8》实验报告的更多相关文章
- [操作系统实验lab3]实验报告
[感受] 这次操作系统实验感觉还是比较难的,除了因为助教老师笔误引发的2个错误外,还有一些关键性的理解的地方感觉还没有很到位,这些天一直在不断地消化.理解Lab3里的内容,到现在感觉比Lab2里面所蕴 ...
- Ucore lab1实验报告
练习一 Makefile 1.1 OS镜像文件ucore.img 是如何一步步生成的? + cc kern/init/init.c + cc kern/libs/readline.c + cc ker ...
- ucore操作系统学习(三) ucore lab3虚拟内存管理分析
1. ucore lab3介绍 虚拟内存介绍 在目前的硬件体系结构中,程序要想在计算机中运行,必须先加载至物理主存中.在支持多道程序运行的系统上,我们想要让包括操作系统内核在内的各种程序能并发的执行, ...
- 《ucore lab3》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1:给未被映射的地址映射上物理页 题目 完成do_pgfault(mm/vmm.c)函数,给未被映射的地址映射上物理页.设置访问权限的时候需 ...
- 《ucore lab1 exercise5》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 题目:实现函数调用堆栈跟踪函数 我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_s ...
- 《ucore lab7》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 理解内核级信号量的实现和基于内核级信号量的哲学家就餐问题(不需要编码) 题目 完成练习0后,建议大家比较一下(可用meld等文件dif ...
- 《ucore lab6》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 使用 Round Robin 调度算法(不需要编码) 题目 完成练习0后,建议大家比较一下(可用kdiff3等文件比较软件) 个人完成 ...
- 《ucore lab5》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1: 加载应用程序并执行(需要编码) 题目 do_execv函数调用load_icode(位于kern/process/proc.c中) 来 ...
- 《ucore lab4》实验报告
资源 ucore在线实验指导书 我的ucore实验代码 练习1:分配并初始化一个进程控制块 题目 alloc_proc函数(位于kern/process/proc.c中) 负责分配并返回一个新的str ...
随机推荐
- Java与设计模式之单例模式(下) 安全的单例模式
关于单例设计模式,<Java与设计模式之单例模式(上)六种实现方式>介绍了6种不同的单例模式,线程安全,本文介绍该如何保证单例模式最核心的作用——“实现该模式的类有且只有一个实 ...
- 【知识点】同样是消息队列,Kafka凭什么速度那么快?
同样是消息队列,Kafka凭什么速度那么快? 作者 | MrZhangxd Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间,但是实际上,Kafk ...
- 9.本地线程(ThreadLoca)
ThreadLoca 提高一个线程的局部变量,访问某个线程都有自己的局部变量,当使用ThreadLoca为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的副本,二不会影响到 ...
- Tkinter 之磁盘搜索工具实战
一.效果图 二.代码 miniSearch.py from tkinter import * from tkinter import ttk, messagebox, filedialog from ...
- Win7如何设置怎样在局域网内共享打印机
首先进入桌面,点击开始按钮,然后打开控制面板 2 在控制面板设置界面,找到“管理工具”选项 3 接着打开“计算机管理” 选择“本地用户和组”的Guest账户 确保Guest账户被禁用 下面 ...
- MySQL Online DDL导致全局锁表案例分析
MySQL Online DDL导致全局锁表案例分析 我这边遇到了什么问题? 线上给某个表执行新增索引SQL, 然后整个数据CPU打到100%, 连接数暴增到极限, 最后导致所有访问数据库的应用都奔溃 ...
- 后端小白的Bootstrap笔记 一
栅格系统 下面这张图是Bootstrap对栅格系统有关系数的规定 什么是栅格体统? 栅格系统是Bootstrap提供的移动优先的网格系统, 各个分界点如上: 576px 720px 992px 120 ...
- 【转】反编译获取任何微信小程序源码(完)
一.前言最近在学习微信小程序开发,半个月学习下来,很想实战一下踩踩坑,于是就仿写了一个阿里妈妈淘宝客小程序的前端实现,过程一言难尽,差不多两周时间过去了,发现小程序的坑远比想象的要多的多!!在实际练手 ...
- 启动项目报错:Unsupported major.minor version 52.0
解决方案: 确保Build Path或者电脑配置的环境变量版本号,和pom中的一致 Exception in thread "main" java.lang.Unsupported ...
- go之web框架 iris
前言 最近开始学习GO的WEB框架,IRIS号称是Go最快的后端Web框架,目前发展最快的Go Web框架.提供完整的MVC功能并且面向未来. 所以先从它开始. github地址 https://gi ...