zoukankan      html  css  js  c++  java
  • ucore-lab1-练习1report

    练习1 report

    问题1OS镜像文件ucore.img是如何一步一步生成的(需要比较详细地解释Makefile中的每一条相关命令和命令参数的含义,以及说明命令导致的结果)?

    1.   GNU make是一种代码维护工具,在大中型项目中,它将根据程序各个模块的更target新情况,自动地维护和生成目标代码。make命令执行时,需要一个Makefile文件,以告诉make命令需要怎样去编译和链接程序。使用Makefile文件时,有如下规则:(1)如果这个工程没有编译过,那么所有的c文件都要编译并链接;2)如果这个工程的某几个c文件被修改,那么只编译被修改的c文件,并链接目标程序;3)如果这个工程的头文件被改变了,那么需要编译引用这几个头文件的c文件,并链接目标程序。

        Makefile文件大致由targetprerequisitescommand组成,target表示要生成的目标文件,prerequisites指要生成target所需要的文件或是目标,commandmake需要执行的命令(shell命令),必须以[tab]开头。只要prerequisites中有一个以上的文件比文件要新,command的指令就会被执行,这就是Makefile的规则。

        2.    编译所有生成bin/kernel所需的文件:

    生成这些.o文件的相关makefile代码为

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

    1) init.c是OS的初始化启动代码,init.c编译名为init.o的中间目标文件-c参数表示生成init.o的目标文件,-o表示生成可执行文件。gcc -c a.c -o a.o表示把源文件a.c编译成指定文件名a.o的中间目标文件。):

    gcc -c kern/init/init.c -o obj/kern/init/init.o

    2) readline.c编译为名为readline的中间目标文件:

    gcc -c kern/libs/readline.c -o obj/kern/libs/readline.o

    3) 编译stdio.c生成stdio.o:

    gcc -c kern/libs/stdio.c -o obj/kern/libs/stdio.o

    4) kdebug.c提供源码和二进制对应关系的查询功能,用于显示调用栈关系。编译kdebug.c生成kdebug.o:

    gcc  -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o       

    5) panic.c提供了panic函数,便于在发现错误后,调用kernel monitor。编译panic.c生成panic.o:

    gcc  -c kern/debug/panic.c -o obj/kern/debug/panic.o

    6) clock.c实现了对时钟控制器8253的初始化操作。编译clock.c生成panic.o:

    gcc  -c kern/driver/clock.c -o obj/kern/driver/clock.o

    7) kmonitor.c实现提供动态分析命令的kernel monitor,便于在ucore出现bug或问题之后,能够进入kernel monitor中,查看当前调用关系。编译kmonitor.c生成kmonitor.o:

    gcc  -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o

    8) console.c实现了对串口和键盘的中断方式的处理操作。将console.c编译生成console.o:

    gcc -c kern/driver/console.c -o obj/kern/driver/console.o

    9) intr.c实现了通过设置CPU的Eflags来屏蔽和使能中断的函数。编译intr.c生成intr.o:

    gcc -c kern/driver/intr.c -o obj/kern/driver/intr.o

    10) picirq.c实现了对控制中断器8259A的初始化和使能操作。编译picriq.c生成picriq.o:

    gcc -c kern/driver/picirq.c -o obj/kern/driver/picirq.o

    11) vectors.S包括256个中断服务例程的入口地址和第一步初步处理时先。此文件是由tools/vector.c在编译ucore期间动态生成的。编译voctor.S生成vector.o:

    gcc -c kern/trap/vectors.S -o obj/kern/trap/vectors.o

    12) trapentry.S紧接着第一步初步处理后,进一步完成第二步初步处理;并且又恢复中断上下文的处理,即中断处理完毕后的返回准备操作。编译trapentry.S生成trapentry.o:

    gcc -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o

    13) trap.c紧接着第二步初步处理后,继续完成具体的各种中断处理操作。编译trap.c生成trap.o:

    gcc -c kern/trap/trap.c -o obj/kern/trap/trap.o

    14) pmm.c设定ucore操作系统在段机制中要用到的全局变量:任务状态栏ts,全局描述符表gdt[],加载全局描述符表寄存器的函数lgdt,临时的内核栈stack(),以及对全局描述符表和任务状态段的初始化函数gdt_init。编译pmm.c生成pmm.o:

    gcc -c kern/mm/pmm.c -o obj/kern/mm/pmm.o

    15) 编译printfmt.c生成printfmt.o:

    gcc -c libs/printfmt.c -o obj/libs/printfmt.o

    16) 编译string.c生成string.o:

    gcc -c libs/string.c -o obj/libs/string.o

     

      3.链接生成bin/kernel:

    生成kernel需要第一步所生成的那些.o文件和kernel.ld,而kernel.ld已经存在。生成kernel的Makefile相关代码为

    $(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)

    ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel

    obj/kern/init/init.o obj/kern/libs/readline.o

    obj/kern/libs/stdio.o obj/kern/debug/kdebug.o

    obj/kern/debug/kmonitor.o obj/kern/debug/panic.o

    obj/kern/driver/clock.o obj/kern/driver/console.o

    obj/kern/driver/intr.o obj/kern/driver/picirq.o

    obj/kern/trap/trap.o obj/kern/trap/trapentry.o

    obj/kern/trap/vectors.o obj/kern/mm/pmm.o

    obj/libs/printfmt.o obj/libs/string.o

    其中ld命令是关键,用于把目标代码文件连接为可执行文件或者库文件

    -m模拟指定的连接器elf_i386;

    -T指定命令文件为tools/kernel.ld,即让连接器使用指定的该脚本;

    -o指定输出文件名字为kernel。 

     

      4.生成bootblock:

    在生成bootblock之前需要生成bootasm.o、bootmain.o、sign:

    1) 生成bootasm.o需要bootasm.S,bootasm.S定义并实现bootloader最先执行的函数start,此函数进行了一定的初始化,完成了从实模式到保护模式的转换,并调用了bootmain.c中的bootmain函数。实际命令为:

    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使用的调试信息。这样才能用qemu+gdb来调试bootloader or ucore;

    -m32:生成适用于32位环境的代码。我们用的模拟硬件是32bit80386,所以ucore也要是32位的软件;

    -gstabs:生成stabs格式的调试信息。这样要ucoremonitor可以显示出便于开发者阅读的函数调用栈信息

    -nostdinc:不使用标准库。标准库是给应用程序用的,我们是编译ucore内核,OS内核是提供服务的,所以所有的服务要自给自足。

    -fno-stack-protector:不生成用于检测缓冲区溢出的代码。

    -Os:为减小代码大小而进行优化。根据硬件spec,主引导扇区只有512字节,我们写的简单bootloader的最终大小不能大于510字节。

    -I<dir>:添加搜索头文件的路径。

    -Wall:产生尽可能多的警告信息。

    -fno-builtin:除非用__builtin_前缀,否则不进行builtin函数的优化

    2) 生成bootmain.o需要bootmain.c,bootmain.c定义并实现了bootmain函数,实现了通过屏幕、串口和并口显示字符串,bootmain函数加载ucore操作系统到内存,然后跳到ucore的入口处执行。实际命令为:

    gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc

      -fno-stack-protector -Ilibs/ -Os -nostdinc

      -c boot/bootmain.c -o obj/boot/bootmain.o

    其参数与前面提到的一致。

    3) 生成sign需要sign.c,sign.c是一个C语言小程序,用于生成一个规范的硬盘主引导扇区。实际命令为:

    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

    关键的参数:

    -I<dir>:添加搜索头文件的路径。

    -Wall:产生尽可能多的警告信息。

    -O2:优化程序。

    -g:生成可供gdb使用的调试信息。

    4) bootasm.o,bootmain.o,sign生成bootblock.o:

    实际命令为:

    ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00

       obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o

    关键的参数:

    -m:模拟指定的连接器为elf_i386;

    -N:指定读取/写入文本和数据段;

    -e:使用指定的符号start作为程序的初始执行点;

    -Ttext:使用指定的地址0x7C00作为文本段的起始点;

    -nonstdlib不使用标准库。

    5) 拷贝二进制代码bootblock.obootblock.out

    objcopy -S -O binary obj/bootblock.o obj/bootblock.out

    关键的参数:

    -S:移除所有符号和重定位信息

    -O <bfdname>:指定输出格式

    6) 使用sign工具处理bootblock.out,生成bootblock

    bin/sign obj/bootblock.out bin/bootblock

       

      5.生成ucore.img:

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

    dd if=/dev/zero of=bin/ucore.img count=10000

    2) bootblock中的内容写到第一个块

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

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

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

    其中dd命令的作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的 转换。第一条命令即将/dev/zero全盘数据,这里用0填充,备份到bin/下的 ucore.img文件。

    关键参数:

    if=文件名:输入文件名,缺省即标准输入;

    of=文件名:输出文件名,缺省即标准输出;

    seek=blocks:从输出文件开头跳过blocks个块后开始复制;

    conv:用指定的参数转换文件,此处的参数notrunc为不截短输出文件。

     

    问题2:一个被认为是符合规范的硬盘主引导扇区的特征是什么?

    通常,我们将包含MBR引导代码的扇区称为主引导扇区。通常由3部分组成:

    主引导程序(MBR,占446字节)、磁盘分区表项(占4×16个字节,负责说明磁盘上的分区情况)、结束标志(占2个字节,其值为AA55)。

    因为sign.c是用于生成一个符合规范的硬盘主引导扇区,所以我截取了sign.c中的部分代码并加以注释来更清晰地分析主引导分区的特征:

    char buf[512];          //定义buff数组

    memset(buf, 0, sizeof(buf));     //buff数组初始化为0            

    buf[510] = 0x55;

    buf[511] = 0xAA;    //buff数组最后两位初始化为0x55,0xAA

    得出主引导扇区的特征:

    1. 大小为512个字节;
    2. 510个字节为0x55;
    3. 511个字节为0xAA;
    4. 其余字节为0。                                                      
  • 相关阅读:
    IOS compare 字符串比较
    Cocoa Touch事件处理流程--响应者链
    真机测试及布署Code Sign error问题总结
    CG_INLINE,inline 内联函数
    objective-c static变量的使用总结
    iOS用户信息单例的创建
    UITextField-修改占位文字和光标的颜色,大小
    iOS应用程序生命周期(前后台切换,应用的各种状态)详解
    深入理解RunLoop
    jQuery文件上传插件uploadify
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/10555468.html
Copyright © 2011-2022 走看看