Lab1实验报告

Lab1实验报告

一、思考题

Thinking1.1

请查阅并给出前述objdump中使用的参数的含义。使用其它体系结构的编译器(如课程平台的MIPS交叉编译器)重复上述各步编译过程,观察并在实验报告中提交相应结果。

objdump中参数:-D:从objfile中反汇编所有的section;-S:尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。

交叉编译:

对于一个文件gpa.c:

int main ()
{
	int point;
	double sum_1, sum_2, sum_3;
	double gpa;
	
	sum_1 = 100 - point;
    
	sum_2 = sum_1 * sum_1 * 3;
	sum_3 = sum_2 / 1600;
	gpa = 4 - sum_3;

	return 0;
}

执行以下指令:

git@20373512:~/20373512$ /OSLAB/compiler/usr/bin/mips_4KC-gcc -c gpa.c
git@20373512:~/20373512$ /OSLAB/compiler/usr/bin/mips_4KC-ld -o gpa gpa.o
git@20373512:~/20373512$ /OSLAB/compiler/usr/bin/mips_4KC-objdump -DS gpa > gpa.txt

输出结果:

004000b0 <main>:
  4000b0:   3c1c0fc0    lui gp,0xfc0
  4000b4:   279c7f40    addiu   gp,gp,32576
  4000b8:   0399e021    addu    gp,gp,t9
  4000bc:   27bdffc8    addiu   sp,sp,-56
  4000c0:   afbe0030    sw  s8,48(sp)
  4000c4:   03a0f021    move    s8,sp
  4000c8:   24030064    li  v1,100
  4000cc:   8fc20028    lw  v0,40(s8)
  4000d0:   00621823    subu    v1,v1,v0
  4000d4:   44830000    mtc1    v1,$f0
  4000d8:   46800021    cvt.d.w $f0,$f0
  4000dc:   f7c00020    sdc1    $f0,32(s8)
  4000e0:   d7c20020    ldc1    $f2,32(s8)
  4000e4:   d7c00020    ldc1    $f0,32(s8)
  4000e8:   46201082    mul.d   $f2,$f2,$f0
  4000ec:   8f828018    lw  v0,-32744(gp)
  4000f0:   d4400140    ldc1    $f0,320(v0)
  4000f4:   46201002    mul.d   $f0,$f2,$f0
  4000f8:   f7c00018    sdc1    $f0,24(s8)
  4000fc:   d7c20018    ldc1    $f2,24(s8)
  400100:   8f828018    lw  v0,-32744(gp)
  400104:   d4400148    ldc1    $f0,328(v0)
  400108:   46201003    div.d   $f0,$f2,$f0
  40010c:   f7c00010    sdc1    $f0,16(s8)
  400110:   8f828018    lw  v0,-32744(gp)
  400114:   d4420150    ldc1    $f2,336(v0)
  400118:   d7c00010    ldc1    $f0,16(s8)
  40011c:   46201001    sub.d   $f0,$f2,$f0
  400120:   f7c00008    sdc1    $f0,8(s8)
  400124:   00001021    move    v0,zero
  400128:   03c0e821    move    sp,s8
  40012c:   8fbe0030    lw  s8,48(sp)
  400130:   27bd0038    addiu   sp,sp,56
  400134:   03e00008    jr  ra
  400138:   00000000    nop
  40013c:   00000000    nop
Thinking1.2

也许你会发现我们的readelf程序是不能解析之前生成的内核文件(内核文件是可执行文件)的,而我们之后将要介绍的工具readelf则可以解析,这是为什么呢?(提示:尝试使用readelf -h,观察不同)

原因:内核文件是大端存储,而我们的readelf程序解析的文件是小端存储的文件。在这里插入图片描述
在这里插入图片描述

Thinking1.3

在理论课上我们了解到,MIPS 体系结构上电时,启动入口地址为0xBFC00000(其实启动入口地址是根据具体型号而定的,由硬件逻辑确定,也有可能不是这个地址,但一定是一个确定的地址),但实验操作系统的内核入口并没有放在上电启动地址,而是按照内存布局图放置。思考为什么这样放置内核还能保证内核入口被正确跳转到?

(提示:思考实验中启动过程的两阶段分别由谁执行。)

操作系统启动时,首先启动bootloader程序,在stage1阶段初始化硬件设备。此时对于MIPS处理器来说,MIPS体系结构上电时,启动入口的地址为0xBFC00000(或为某一个确定的地址),为一个虚拟地址,在kseg1中。将虚拟地址的高三位清零之后,对应的物理地址为0x1FC00000,从这里开始MIPS的第一条指令,完成初始化基本的硬件设备的工作和为stage2做准备。

之后进入stage2阶段的入口函数,BIOS从MBR中读取开机信息,以Linux中的GRUB开机管理程序为例,BIOS加载MBR中的GRUB代码后把CPU交给GRUB,GRUB一步一步加载自身代码,从而识别文件系统,然后将文件系统中的内核镜像文件加载到内存中,此时会有一个内存移动的操作,最后BIOS跳到指定的地址运行,这样便可以保证内核入口被正确跳转到。

Thinking1.4

与内核相比,普通进程的sg_size 和bin_size 的区别在于它的开始加载位置并非页对齐,同时bin_size的结束位置(va+i,其中i为计算出的该段在ELF文件中的大小)也并非页对齐,最终整个段加载完毕的sg_size 末尾的位置也并非页对齐。请思考,为了保证页面不冲突(不重复为同一地址申请多个页,以及页上数据尽可能减少冲突),这样一个程序段应该怎样加载内存空间中。

可以采用段式存储的方式,变线性地址为二维的地址,以便于将不同的页在空间上分隔开。

Thinking1.5

内核入口在什么地方?main 函数在什么地方?我们是怎么让内核进入到想要的 main 函数的呢?又是怎么进行跨文件调用函数的呢?

内核入口位于0x80000000处;

main函数位于0x80010000处;

在内核的入口处修改跳转指令的地址,再利用jal指令跳转,就可以让内核 进入到想要的main函数;

在跨文件调用函数时,先将原来的变量和返回地址入栈,之后跳转到想调用的函数的地址,函数调用结束后再将要返回的地址出栈并返回,之后使原来的变量也出栈并恢复。

Thinking1.6

查阅《See MIPS Run Linux》一书相关章节,解释boot/start.S 中下面几行对CP0 协处理器寄存器进行读写的意义。具体而言,它们分别读/写了哪些寄存器的哪些特定位,从而达到什么目的?

/* Disable interrupts */
mtc0 zero, CP0_STATUS
......
/* disable kernel mode cache */
mfc0 t0, CP0_CONFIG
and t0, ~0x7
ori t0, 0x2
mtc0 t0, CP0_CONFIG

mtc0 zero, CP0_STATUS写CP0寄存器,将CP0寄存器初始化为零;

mfc0 t0, CP0_CONFIG读CP0寄存器,并将值存入t0中;

and t0, ~0x7将后三位清零;

ori t0, 0x2将后三位变为010,010可以决定固定kseg0的域是否进入缓存;

mtc0 t0, CP0_CONFIG写CP0寄存器,将t0的值写入。

通过以上操作可以禁用内核缓存模式。

二、实验难点图示

本次实验难点主要有两点。

第一点在于exercise1.2中ELF文件的结构:

在这里插入图片描述

  • 要了解ELF文件在编译和运行两种视角下的不同结构及他们之间的关系
  • 要理解ELF文件之中的三个结构体并利用文件头地址和偏移量求地址

第二点在于exercise1.5中print.c中lp_Print函数的流程:

在这里插入图片描述

  • 注意是按照%[flags][width][.precision][length]specifier这样的顺序进行的,不能够打乱
  • 要重点理解代码中出现的函数的作用,搞清楚重要变量的作用
  • 注意多个输出的即 % XXXX % XXXX这种功能,也就是说可以多个输出,直到读到’\0’后才结束
  • 注意要将padc,ladjust等标志作用的变量都赋给初值,尤其是padc初值为’ ’
  • 我的一个bug是检验*fmt是否为%时没有同时确保fmt不是’\0’以至于出错

三、体会与感想

lab1的实验进行了两周,第一周考查的是elf文件相关的知识,因为这个对我来说比较陌生,所以花费了不少的时间去理解。可能是被计组搞得有点ptsd,以至于课下花了大约有七八小时的时间学习这一部分,上机前心里还是特别慌,但是没想到五分钟就把exam做出来了,然后花两个小时做extra还没做出来Orz。

第二周考察的是写一个printf,这部分我学习的时间倒是没有elf长,花费六小时左右。MIPS的内容在学计组时就接触过很多,因此不难理解,printf相当于考察C语言指针的使用,加上注释写的比较详细,因此完成也不困难。这一部分对操作系统内核的理解很重要,但是却不是难点,我觉得难点在于C语言指针的使用,上机考试因为对结构体指针的不熟悉再加上对那几个.c文件的不理解所以挂掉了wuwu…

这次实验也学到了很多,第一是关于Makefile的使用以及make和make clean的操作;第二是关于内核地址与MIPS的结合,.data和.text在上学期学计组时就一直存疑,学的不是很明白,经过lab1的学习明朗了很多;第三是关于MIPS与栈,MIPS中函数的调用与返回,以及相关的进栈出栈操作,也是上学期计组留下的坑🕳;第四就是对大段代码的理解能力有所提升,对C语言之间各个.c文件的相互调用,以及.h头文件有了新的认识。

总的来说,lab1给我的教训就是,还是要重视C语言,尤其重视C语言指针的使用。怎么说呢,其实之前就听过学长的建议,说C语言指针对os学习很重要,其实考前也有去复习,但是由于大一C语言基础确实很差所以一时半会确实很难学精,加上oo夹击所以对这次上机有点轻视了,很惨痛的教训,而且lab1就挂掉了说实话打击还是挺大的,希望以后的lab更加努力吧。

四、指导书反馈

有一点有个小小的疑惑,在exercise1.5写printf的时候,注释里把检查是否是long放的比较靠前,但是按照printf的格式化描述,应该是%[flags][width][.precision][length]specifier这样的顺序,所以检查是否为long int 的位置应该比较靠后。

对于像我这种几乎是看着注释写代码的,就因为判断的顺序问题而找了很久的bug。不知道这是助教gg们的小失误,还是有意而为之,警告我们不要看着注释写代码嘛。

五、残留难点

第一次上机extra有遇到memsz和filesz,不太懂两者区别;

ELF文件内容很多,仅仅教程里讲到的可能还是不足以让我完全理解,不过课程网站上给的ELF参考资料很有用,由于时间原因还没有看完,以后会接着理解;

其次是目前还是看不太懂几个print.c、printf.c、print.h、printf.h几个文件之间的关系;

对于gxemul的使用还是不太会,因为我是按照main函数里改printf的方法调试的,几乎没有用过gxemul。

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值