BUAA OS——Lab1实验报告

lab1实验报告

实验思考题

1.1

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

​ 通过linux内置的readelf工具即使用readelf -h命令行分别对testELF文件和之前生成的内核文件vmlinux的elf文件头进行查看:

可以很清楚的看出,之前生成的vmlinux内核文件为大端存储,而testELF为小端存储。

因此我们自己编写的readelf程序只能解析testELF而不能解析vmlinux内核文件,因为编写readelf程序使用c语言不能简单的读取大端存储的数据。

1.2

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

内核的入口的起始地址为0x80000000,main函数在0x80010000。

在入口函数本实验为start.S内部使用跳转指令jal跳转到指定的函数地址。跨文件调用函数通过跳转指令来调用,同时在跳转之前需要将数据存入栈中。


实验难点图示

本次课下实验的难点其实就是能否读懂现有代码以及学习如何调用现有的工具。

例如在编写readelf.c文件中,我们可以从ELF手册中得知每个elf文件头结构体的结构,以及它内部的数据,随后根据适当的处理得出每个Section的结构体,再从其中获取所需要的数据。

即思路可以概括为一下步骤:

  • 知道结构体中的数据
typedef struct {
    unsigned char   e_ident[EI_NIDENT];     /* Magic number and other info */
    // 存放魔数以及其他信息
    Elf32_Half      e_type;                 /* Object file type */
    // 文件类型 
    Elf32_Half      e_machine;              /* Architecture */
    // 机器架构
    Elf32_Word      e_version;              /* Object file version */
    // 文件版本
    Elf32_Addr      e_entry;                /* Entry point virtual address */
    // 入口点的虚拟地址
    Elf32_Off       e_phoff;                /* Program header table file offset */
    // 程序头表所在处与此文件头的偏移
    Elf32_Off       e_shoff;                /* Section header table file offset */
    // 段头表所在处与此文件头的偏移
    Elf32_Word      e_flags;                /* Processor-specific flags */
    // 针对处理器的标记
    Elf32_Half      e_ehsize;               /* ELF header size in bytes */
    // ELF文件头的大小(单位为字节)
    Elf32_Half      e_phentsize;            /* Program header table entry size */
    // 程序头表入口大小
    Elf32_Half      e_phnum;                /* Program header table entry count */
    // 程序头表入口数
    Elf32_Half      e_shentsize;            /* Section header table entry size */
    // 段头表入口大小
    Elf32_Half      e_shnum;                /* Section header table entry count */
    // 段头表入口数
    Elf32_Half      e_shstrndx;             /* Section header string table index */
    // 段头字符串编号
} Elf32_Ehdr;
  • 了解readelf.c文件中已有代码如何获取结构体中的数据
  • 仿照已有代码获取所需要的数据:e_shoffe_shentsizee_shnum

再例如补全print.c文件中的代码,需要的也是这种思路:

  • 了解已有的specifier的处理过程
  • 查看已有的printNumprintChar等方法
  • 获取所需要的各种参数
  • 仿照已有的specifier的处理过程,对d、D进行处理
  • 同时需要充分熟悉有关C语言指针的知识

而对于更多的细节,对于本次实验练习关系并不是很大,只需要大致了解内核启动和编译链接的过程。但是,为了 更好的理解和熟悉相关的步骤,需要仔细阅读每一部分的代码,了解每部分代码所充当的角色和内容


体会与感想

  • 最大的体会就是,操作系统这一门课,与其说是理解软硬件之间是如何进行交互的,不如说是C语言与汇编的从入门到精通到再精通。因为c语言代码随处可见,许多指针以及结构体调用和传递是穿插在整个操作系统的。
  • 操作系统的启动规则很复杂且重要。一种操作系统不只是也不可能只属于一台机器的,为了可移植性,需要对操作系统的各个行为都进行严格的规范,启动这一步骤同样,内存分配、加载内核等行为拥有很庞大的规则,而了解和熟知这些规则需要耗费大量的时间和经理。同时我也感叹到这些规则的逻辑严谨并且非常清晰,是许多次不断探索的结果。
  • 按照已有的规定去编写代码,既简单又麻烦。简单是因为你不需要去思考规范问题,麻烦是规则并不符合自己的编程习惯,因此需要花更多精力去适应这种过程。
posted @ 2021-08-15 17:11  Fight扬尘  阅读(1039)  评论(0)    收藏  举报