Lab1 Report

Lab1 Report

思考题

Thinking 1.1

  • 请阅读附录中的编译链接详解,尝试分别使用实验环境中的原生 x86 工具链(gcc、ld、readelf、objdump 等)和 MIPS 交叉编译工具链(带有 mips-linux-gnu- 前缀),重复其中的编译和解析过程,观察相应的结果,并解释其中向 objdump 传入的参数的含义。
    • 编译程序 hello.c,再用 objdump 反编译.o 与可执行文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    x86:
    gcc -c hello.c 生成 hello.o 文件
    gcc -o hello_x86 hello.c 链接
    objdump -DSt hello.o x86 工具链反编译 x86 下的.o 文件
    objdump -DSt hello_x86 x86 工具链反编译 x86 下的可执行文件
    mips-linux-gnu-objdump -DSt hello.o :can't disassemble for architecture UNKNOWN!
    mips-linux-gnu-objdump -DSt hello_x86 :can't disassemble for architecture UNKNOWN!

    =>mips-linux-gnu- 工具链不可反编译 x86 下的.o 与可执行文件

    MIPS 交叉编译工具链:
    mips-linux-gnu-gcc -c hello.c 生成 hello.o 文件
    mips-linux-gnu-gcc -o hello_mips hello.o 链接
    objdump -DSt hello.o x86 工具链反编译 mips 下的.o 文件
    objdump -DSt hello_mips x86 工具链反编译 mips 下的可执行文件
    mips-linux-gnu-objdump -DSt hello.o mips-linux-gnu- 工具链工具链反编译 mips 下的.o 文件
    mips-linux-gnu-objdump -DSt hello_mips >mips-linux-gnu- 工具链反编译 mips 下的可执行文件


    -D
    --disassemble-all
    与 -d 类似,但反汇编所有 section.

    -S
    --source
    尽可能反汇编出源代码,尤其当编译的时候指定了 -g 这种调试参数时,效果比较明显。隐含了 -d 参数。

    -t:显示可执行文件的符号表。
    • 反编译.o 文件时某一些指令的地址为 0,没有取得应有的地址,但在链接成为可执行文件后,则被填入地址。
    • 通过观察不同工具链编译出的可执行文件和使用 objdump 解析的结果,可以发现它们在汇编指令和符号表等方面存在差异。不同的工具链可能使用不同的指令集,因此编译出的可执行文件也会有所不同。

Thinking 1.2

  • 尝试使用我们编写的 readelf 程序,解析之前在 target 目录下生成的内核 ELF 文件。

    • readelf 解析之前在 target 目录下生成的内核 ELF 文件结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    0:0x0
    1:0x80400000
    2:0x80401a80
    3:0x80401a98
    4:0x80401ab0
    5:0x0
    6:0x0
    7:0x0
    8:0x0
    9:0x0
    10:0x0
    11:0x0
    12:0x0
    13:0x0
    14:0x0
    15:0x0
    16:0x0
  • 也许你会发现我们编写的 readelf 程序是不能解析 readelf 文件本身的,而我们刚才介绍的系统工具 readelf 则可以解析,这是为什么呢?(提示:尝试使用 readelf-h,并阅读 tools/readelf 目录下的 Makefile,观察 readelf 与 hello 的不同)

    • 使用 readelf -h 得到两个文件文件头差异

    image-20230307161525500

    • 编写的 readelf 中 Elf32_Ehdr 等针对的是 32 位的 ELF 的解析,hello 程序 ELF 类别是 32 位,可被编写的 readelf 解析,但 readelf 文件本身位 64 位 ELF,不可被解析。系统工具则都可解析

Thinking 1.3

  • 在理论课上我们了解到,MIPS 体系结构上电时,启动入口地址为 0xBFC00000(其实启动入口地址是根据具体型号而定的,由硬件逻辑确定,也有可能不是这个地址,但一定是一个确定的地址),但实验操作系统的内核入口并没有放在上电启动地址,而是按照内存布局图放置。思考为什么这样放置内核还能保证内核入口被正确跳转到?(提示:思考实验中启动过程的两阶段分别由谁执行。)
    • 在实验操作系统的启动过程中,有一个引导加载程序的阶段。引导加载程序位于启动入口地址处,它的作用是将内核从磁盘中加载到内存中,并将控制权转移到内核入口地址。实验操作系统的内核入口地址放置在内存布局图的正确位置时,引导加载程序可以正确地将控制权转移到内核入口地址处,进入内核。
    • 因此,尽管内核入口地址不是启动入口地址,但通过引导加载程序的正确执行,内核入口仍然可以被正确地跳转到。

难点分析

  • 理解整体架构,查找、理解所需内存配置信息与关联函数参数使用,如:
    • 1.1 中查找各个结构体中成员表示的含义,对应 ELF 文件结构。节头中的地址信息需要通过 binary ELF 的文件头地址 +shoff 为入口偏移 + 节头数 * 节头大小 e_shentsize 得到当前节头地址,再通过该节头结构体中的 sh_addr 得到节头中的地址信息。
    • 1.4 中 printk 时第三个参数传入的是 unsigned long,十进制有符号数需要提前判断是否为负数,取绝对值,提出负号单独处理
  • 1.4 中 c 的语法和与逻辑,一些指针的使用,以及一点点 mips 的语法

实验体会

  • 体会到内核设计运行的复杂与严谨,内存信息需有序规划分配。以及多种类型文件的不同方式的编译,分别负责整体的不同功能方面。
  • 体会到一些 c 语言的强大的灵活基础能力
  • 记得要读网站上的题目,以及教程 exercise 上下文的信息提示,如“Note 1.3.5 通过查看内存布局图,同学们应该能找到.text 节的加载地址了,.data 和.bss 只需要紧随其后即可。”