操作系统实验lab1

本文详细介绍了ucore操作系统实验lab1的过程,包括理解make生成执行文件的步骤,分析硬盘主引导扇区规范,使用qemu执行并调试,分析bootloader进入保护模式的流程,加载ELF格式的操作系统过程,以及实现函数调用堆栈跟踪和中断初始化处理。内容涵盖Makefile解析,BIOS执行,GDT设置,ELF加载,中断处理等多个方面。
摘要由CSDN通过智能技术生成

基于ucore的操作系统实验lab1

Exercise1:理解通过make生成执行文件的过程。

Question1:

操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)
Answer:
在Makefile中生成ucore.img的代码是:

$(UCOREIMG): $(kernel) $(bootblock)
    $ (V)dd if=/dev/zero of=$@ count=10000
    $ (V)dd if=$(bootblock) of=$@ conv=notrunc
    $ (V)dd if=$(kernel) of=$@ seek=1 conv=notrunc

在执行Makefile时对应的输出为:

 1     dd if=/dev/zero of=bin/ucore.img count=10000
 2     10000+0 records in
 3     10000+0 records out
 4     5120000 bytes (5.1 MB) copied, 0.0540315 s, 94.8 MB/s
 5     dd if=bin/bootblock of=bin/ucore.img conv=notrunc
 6     1+0 records in
 7     1+0 records out
 8     512 bytes (512 B) copied, 0.000110706 s, 4.6 MB/s
 9     dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
10  138+1 records in
11  138+1 records out
12   70775 bytes (71 kB) copied, 0.000472623 s, 150 MB/s

从Makefile中可以看出要生成ucore.img首先要拥有kernel和bootblock两个可执行文件

所以继续在Makefile中找到kernel的相关代码段

kernel = $(call totarget,kernel)

$(kernel): tools/kernel.ld

$(kernel): $(KOBJS)
    @echo + ld $@
    $ (V) $ (LD) $ (LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)
    @ $ (OBJDUMP) -S $ @ > $ (call asmfile,kernel)
    @ $ (OBJDUMP) -t $ @ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^ $$/d' > $(call symfile,kernel)

$(call create_target,kernel)

再结合前面的对kernel的一些声明:

#kernel

KINCLUDE    += kern/debug/ \
               kern/driver/ \
               kern/trap/ \
               kern/mm/

KSRCDIR     += kern/init \
               kern/libs \
               kern/debug \
               kern/driver \
               kern/trap \
               kern/mm

KCFLAGS     += $ (addprefix -I,$(KINCLUDE))

$ (call add_files_cc,$ (call listf_cc,$ (KSRCDIR)),kernel,$(KCFLAGS))

查看文件中的文件得出,生成kernel需要以下文件:

kernel.ld    init.o  readline.o  stdio.o     kdebug.o   kmonitor.o panic.o clock.o console.o intr.o  picirq.o   trap.o  trapentry.o  vectors.o  pmm.o  printfmt.o   string.o

根据已有的文件,kernel.ld已经存在,其他的.o文件则需要.c和.s文件通过gcc编译生成

生成init.o需要的命令:

gcc -Ikern/init/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o

生成其他.o文件的命令和init.o的方法类似。

生成这些.o文件后便可以生成kernel可执行文件

而除kernel外还需要生成bootblock

在Makefile中bootblock的相关代码:

#create bootblock
bootfiles = $(call listf_cc,boot)
$ (foreach f,$ ( bootfiles),$ (call cc_compile,$(f),$ (CC),$(CFLAGS) -Os -nostdinc))

bootblock = $ (call totarget,bootblock)

$(bootblock): $ (call toobj,$(bootfiles)) | $ (call totarget,sign)
    @echo + ld $@
    $ (V) $ (LD) $ (LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
    @ $ (OBJDUMP) -S $ (call objfile,bootblock) > $ (call asmfile,bootblock)
    @ $ (OBJCOPY) -S -O binary $ (call objfile,bootblock) $ (call outfile,bootblock)
    @$(call totarget,sign) $(call outfile,bootblock) $(bootblock)

$(call create_target,bootblock)

结合文件夹中的文件可以看出要生成bootblock需要bootasm.o、bootmain.o、sign三个文件

生成bootasm.o的相关代码为:

gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o

其中相关参数的含义为:

ggdb 生成可供gdb使用的调试信息
-m32生成适用于32位环境的代码
-gstabs 生成stabs格式的调试信息
-nostdinc 不使用标准库
-fno-stack-protector 不生成用于检测缓冲区溢出的代码
-0s 位减小代码长度进行优化
生成sign的相关代码为:

gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o
gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign
这些都生成完毕之后就可以开始生成ucore.img

生成ucore.img过程中产生的信息:

dd if=/dev/zero of=bin/ucore.img count=10000
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB) copied, 0.0540315 s, 94.8 MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000110706 s, 4.6 MB/s
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
138+1 records in
138+1 records out
70775 bytes (71 kB) copied, 0.000472623 s, 150 MB/s

生成一个有10000个块的文件,每个块默认512字节,用0填充

dd if=/dev/zero of=bin/ucore.img count=10000
把bootblock中的内容写到第一个块

dd if=bin/bootblock of=bin/ucore.img conv=notrunc

从第二个块开始写kernel中的内容

dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc

Question2:

一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?

Answer:

从sign.c中的:

if (size != 512) {
        fprintf (stderr, "write '%s' error, size is %d.\n", argv[2], size);
        return -1;
    }

可以看出,要求硬盘主引导扇区的大小时512字节

buf[510] = 0x55;
buf[511] = 0xAA;

可以看出,还需要第510个字节是0x55,第511个字节为0xAA,也就是说扇区的最后两个字节内容是0x55AA

Exercise2:使用qemu执行并调试lab1中的软件。

Question1:

从CPU加电后执行的第一条指令开始,单步跟踪BIOS的执行。
Answer:
根据附录中的说明, 修改 lab1/tools/gdbinit,

set architecture i8086
target remote :1234
在 lab1目录下,执行

make debug

这时GDB停在BIOS的第一条指令出,可能是由于不兼容的问题,无法正常显示出指令,只看得到地址为0xe05b,而指令码却显示为??

然后输入si单步执行,也是只能看到地址,但指令显示为??

所以使用

x/5i 0xffff0

Question2:

在初始化位置0x7c00设置实地址断点,测试断点正常在gdb中输入一下命令

在gdb中输入一下命令

b *0x7c00 

//在0x7c00处设置断点。此地址是bootloader入口点地址,可看boot/bootasm.S的start地址处

c         

//continue简称,表示继续执行

x /2i $pc 

//显示当前eip处的汇编指令
得到

Breakpoint 2,
0x00007c00 in ?? ()

=> 0x7c00:      cli   


   0x7c01:      cld 

Question3:

从0x7c00开始跟踪代码运行,将单步跟踪反汇编得到的代码与bootasm.S和 bootblock.asm进行比较。

Answer:

​ 在0x7c00处break,然后使用si和 x/i $pc 指令一行一行的跟踪,将得到的反汇编代码为:

0x00007c01 in ?? ()
(gdb) x/i $pc
=> 0x7c01:      cld    
(gdb) si
0x00007c02 in ?? ()
(gdb) x/i $pc
=> 0x7c02:      xor    %eax,%eax
(gdb) si
0x00007c04 in ?? ()
(gdb) x/i $pc
=> 0x7c04:      mov    %eax,%ds
(gdb) 

bootblock.asm 中的代码为:

.# code16                                             # Assemble for 16-bit mode
    cli                                             # Disable interrupts
    7c00:   fa                      cli    
    cld                                             # String operations increment
    7c01:   fc                      cld    

    # Set up the important data segment registers (DS, ES, SS).
    xorw %ax, %ax                                   # Segment number zero
    7c02:   31 c0                   xor    %eax,%eax
    movw %ax, %ds                                   # -> Data Segment
    7c04:   8e d8                   mov    %eax,%ds
    movw %ax, %es                                   # -> Extra Segment
    7c06:   8e c0                   mov    %eax,%es
    movw %ax, %ss                                   # -> Stack Segment
    7c08:   8e d0                   mov    %eax,%ss

bootasm.s中的代码为:

.globl start
  start:
  .code16                                             # Assemble for 16-bit mode
    cli                                             # Disable interrupts
    cld                                             # String operations increment

    # Set up the important data segment registers (DS, ES, SS).
    xorw %ax, %ax          
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值