操作系统lab0
作者:王赛宇
操作系统
我这里用的是Ubuntu 20.04 LTS
,这个不强求吧,从16.04
到20.04
应该都没问题。这边是双系统,因为早就装好了,所以就不装虚拟机了。
C语言
sudo apt-get install gcc
这个不多谈了,直接给个文件吧
test.c
#define GLOBAL_NUM 10
#include<stdio.h>
int glo_var;
void funcA(){
printf("funA:");
int a[GLOBAL_NUM];
for(int i=0;i<GLOBAL_NUM;i++)
a[i] = i;
}
int main(){
funcA();
return 0;
}
Makefile
sudo apt-get install makefile
Makefile其实非常像是一个脚本文件,你可以在makefile文件中书写一些脚本,然后再使用make命令去执行他们,比如下面的makefile。
test: test.o
gcc -g -o test test.o
test.o: test.c
gcc -g -c -o test.o test.c
clean:
rm -rf ./test.o ./test
可以说这个makefile已经包含了一些必要的makefile知识了(其实简单使用makefile不需要啥知识。。),首先我们可以在控制台中输入make
来执行该脚本。输入make时,会执行第一条指令,也就是test: test.o
,这句话的意思是,要执行test,执行test需要依赖于test.o
,于是就会先执行test.o
对应的部分,于是执行了:gcc -g -c -o test.o test.c
,生成了test.o
,生成test.o
后满足了test
的条件,于是执行:gcc -g -o test test.o
,生成了test
,也就是可执行文件。
如果想要重新生成,就可以使用make clean
语句,make clean
实质上是调用了自己已经在Makefile
中定义好的脚本:rm -rf ./test
。同理,我们也可以使用make test.o
来单独生成test.o
文件。
执行效果:
# wangsy @ wangsaiyu in ~/Study/HomeWork/os/LAB1_release_v1.0/docs [10:47:55]
$ make
gcc -g -c -o test.o test.c
gcc -g -o test test.o
# wangsy @ wangsaiyu in ~/Study/HomeWork/os/LAB1_release_v1.0/docs [10:47:58]
$ ls
Makefile README.md test test.c test.o
可以看到,执行make后,脚本为我们执行了两条语句
gcc -g -c -o test.o test.c
gcc -g -o test test.o
使用查看当前文件夹命令ls
,看到编译的test.o
以及test
可执行文件已经生成完毕。
再使用:
# wangsy @ wangsaiyu in ~/Study/HomeWork/os/LAB1_release_v1.0/docs [10:47:59]
$ make clean
rm -rf ./test.o ./test
# wangsy @ wangsaiyu in ~/Study/HomeWork/os/LAB1_release_v1.0/docs [10:50:06]
$ ls
Makefile README.md test.c
clean时,执行我们预定义好的脚本进行删除,使用ls
语句检查,发现已经删除完毕。
gdb
sudo apt-get install gdb
gdb是一款调试工具,我们就不多bb,直接看怎么用吧,我们刚才生成了一个叫做test的可执行文件,我们使用gdb test
来制定对test
进行调试,打开时界面如下:
# wangsy @ wangsaiyu in ~/Study/HomeWork/os/LAB1_release_v1.0/docs [10:51:46]
$ gdb test
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
(gdb)
(gdb)
list指令查看代码
我们首先使用list
指令来查看我们调试的代码:
(gdb) list
1 #define GLOBAL_NUM 10
2 #include<stdio.h>
3 int glo_var;
4 void funcA(){
5 printf("funA:");
6 int a[GLOBAL_NUM];
7 for(int i=0;i<GLOBAL_NUM;i++)
8 a[i] = i;
9 }
10 int main(){
(gdb)
这里一次只会显示十行,如果你还想继续看那就继续list。
break指令设置断点
如果不设置断点,那么程序就会直接跑完,那我们就无法调试了,所以调试之前是需要设置断点的。我们可以使用break
指令来设置断点,在这个程序中,我们想看一下a[i] = i
的这一句话反复发生时,i, a[i]
的变化,所以我们将断点打在第8行,为此,输入下面的语句:
(gdb) break 8
Breakpoint 1 at 0x119e: file test.c, line 8.
同时,我们也可以根据函数名设置断点,比如我们想在进入mian()
函数时停留,那就输入:
(gdb) break main
Breakpoint 2 at 0x11cb: file test.c, line 10.
当然,还有很多其他打断点的方法,大家可以自行了解,这里讲太多反而不好理解。
info查看一些信息
这里我们只查看设置过的断点,我们使用info break
方法,来看一下我们设置了哪些断点:
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000000119e in funcA at test.c:8
2 breakpoint keep y 0x00000000000011cb in main at test.c:10
那么这里也非常明显了,我们在第8行设置过一个断点,在第10行的main函数处也设置过断点。
delete删除断点
我们仔细一想,进了main()
函数后就直接进funcA
了,那在main函数处设置断点好像也没啥用,那就把这个断点删了吧,就用下面的语句:
(gdb) delete 2
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000000119e in funcA at test.c:8
这里删除的时候,我们使用断电的编号作为索引进行删除。
run 运行程序
断点终于打好了,接下来我们想看看这些变量在程序跑起来的时候究竟是怎么变的,于是我们使用run指令:
(gdb) run
Starting program: /home/wangsy/Study/HomeWork/os/LAB1_release_v1.0/docs/test
Breakpoint 1, funcA () at test.c:8
8 a[i] = i;
程序会在遇到断点时停下,停下后,我们就可以进行一些操作了
print 查看变量
这里第一次执行到a[i] = i
,这个时候我们想看一下这时候的i和a[i]
分别是多少。
(gdb) print i
$1 = 0
(gdb) print a[i]
$2 = -9306
我们发现,这时候已经进入了循环,所以i
已经被初始化为0,但是程序遇到断点时,a[i] = i
的语句还没有执行,所以a[i]
即a[0]
现在仍然是一个任意值。这警醒我们定义局部变量记得初始化。。。
continue继续执行
我们刚才看了一下第一次执行a[i] = i
的时候a[i],i
分别是什么值,接下来想看一下a[i],i
在第二次是多少,这个时候我们就需要让程序继续执行:
(gdb) continue
Continuing.
Breakpoint 1, funcA () at test.c:8
8 a[i] = i;
(gdb) print i
$3 = 1
(gdb) print a[i]
$4 = 32767
(gdb) print a[0]
$5 = 0
可以看到,这里我们使用continue指令让程序继续执行,程序再次执行到断点时停住了,这时候调用print方法,查看i = 1, a[i] = a[1] = 32767, a[0] = 0
,这说明,第一次查看的那个语句赋值已经完成了,而且经过一轮循环后,i增加了1,但是当前的语句还是没有执行的,所以看到的a[i]
还是一个随机数。
quit 拜拜了
可以看到这里要循环10次,但是我们看了两次就已经悟出了道理了,所以剩下八次就没必要一直看了,这里使用quit
方法就可以退出gdb了:
(gdb) quit
A debugging session is active.
Inferior 1 [process 4957] will be killed.
Quit anyway? (y or n) y
当然,这里的程序还在执行,gdb询问我们,如果现在退出,会杀死正在进行的进程,我们是否同意,我们当然同意,输入y
,然后按回车就可以了。
qemu
sudo apt-get install qemu-system qemu
安装完成后输入qemu
,然后再按TAB
键自动补全,即可出现:
# wangsy @ wangsaiyu in ~ [11:18:00] C:127
$ qemu-nbd
qemu-img qemu-system-microblaze qemu-system-riscv64
qemu-io qemu-system-microblazeel qemu-system-s390x
qemu-make-debian-root qemu-system-mips qemu-system-sh4
qemu-nbd qemu-system-mips64 qemu-system-sh4eb
qemu-pr-helper qemu-system-mips64el qemu-system-sparc
qemu-system-aarch64 qemu-system-mipsel qemu-system-sparc64
qemu-system-alpha qemu-system-moxie qemu-system-tricore
qemu-system-arm qemu-system-nios2 qemu-system-unicore32
qemu-system-cris qemu-system-or1k qemu-system-x86_64
qemu-system-hppa qemu-system-ppc qemu-system-xtensa
qemu-system-i386 qemu-system-ppc64 qemu-system-xtensaeb
qemu-system-lm32 qemu-system-ppc64le
qemu-system-m68k qemu-system-riscv32
我们要模拟的架构应该是qemu-system-x86_64
吧,那就进入到学长给的LAB0_TEST
中,输入:qemu-system-x86_64 -hda ucore.img -parallel stdio
就可以打开虚拟机了。
其他部分我们就不讲了,那些看指导书就ok。
其他想说的
下个git学着用用吧,很好用的
sudo apt-get install git
这个最好配合着GitHub
或者Gitee
或者Coding
之类的平台来用。非常适合一个小组以合作的形式来进行推进。