1.实验目的。
2.实验内容。
2.1Exercise 1.1 请修改 include.mk 文件,使交叉编译器的路径正确。之后执行 make指令,如果配置一切正确,则会在gxemul 目录下生成vmlinux 的内核文件。
修改路径为 /OSLAB/compiler/usr/bin/mips_4KC-
查看gxemul文件夹
实验一完成。
2.2Exercise1.2 阅读./readelf文件夹中kerelf.h readelf.c以及 main.c三个文件中的代码,并完成readelf.c中缺少的代码,readelf 函数需要输出elf 文件的所有section header的序号和地址信息,对每个 section header,输出格式为:"%d:0x%x\n",两个标识符分别代表序号和地址。
1.ELF的定义
ELF(Executable and Linkable Format)文件是一种目标文件格式,常见的ELF格式文件包括:可执行文件、可重定位文件(.o)、共享目标文件(.so)、核心转储文件等。ELF主要用于Linux平台,Windows下是PE/COFF格式。
2.ELF文件头
ELF文件头位于ELF文件的起始位置,它包含整个文件的静态信息,可以通过readelf命令进行查看,ELF文件头结构以及相关参数定义在/usr/include/elf.h中,分为32位和64位两种版本,分别为Elf32_Ehdr和Elf_64_Ehdr,它们绝大多数内容都是一样的,结构如下所示:
typedef struct { Elf32_Half e_type;//Elf文件类型 Elf32_Half e_machine;//ELF文件的CPU平台属性 Elf32_Word e_version;//ELF版本信息 Elf32_Addr e_entry;//入口地址 Elf32_Off e_phoff;//程序头表的文件偏移(以字节为单位)。如果文件没有程序头表,则此成员值为零。 Elf32_Off e_shoff;//节头表的文件偏移(以字节为单位)。如果文件没有节头表,则此成员值为零。 Elf32_Word e_flags;//与文件关联的特定于处理器的标志。标志名称采用 EF_machine_flag 形式。 Elf32_Half e_ehsize;//ELF 头的大小(以字节为单位) Elf32_Half e_phentsize;//文件的程序头表中某一项的大小(以字节为单位)。所有项的大小都相同 Elf32_Half e_phnum;//程序头表中的项数。 Elf32_Half e_shentsize;//节头的大小(以字节为单位)。节头是节头表中的一项。所有项的大小都相同 Elf32_Half e_shnum;//节头表中的项数 Elf32_Half e_shstrndx;//与节名称字符串表关联的项的节头表索引。 } Elf32_Ehdr;
补全readelf.c中代码:
编译与执行:
2.3Exercise 1.3 填写 tools/scse0_3.lds 中空缺的部分,将内核调整到正确的位置上。
注意目标代码文件的内容是由section组成的,而可执行文件的内容是由segment组成的。要注意区分段(segment)和节(section)的概念,这两个概念在后面会经常提到。我们写汇编程序时,用.text,.bss,.data这些指示,都指的是section,比如.text
,告诉汇编器后面的代码放入.text section中。
目标代码文件中的section和sction header table中的条目是一一对应的。section的信息用于链接器对代码重定位。而文件载入内存执行时,是以segment组织的,每个segment对应ELF文件中program header table中的一个条目,用来建立可执行文件的进程映像。比如我们通常说的,代码段、数据段是segment,目标代码中的section会被链接器组织到可执行文件的各个segment中。.text section的内容会组装到代码段中,.data, .bss等节的内容会包含在数据段中。
补全scse_03.lds
生成vmlinux文件
查看各section地址
2.4Exercise 1.4 完成 boot/start.S 中空缺的部分。设置栈指针,跳转到 main函数。使用/OSLAB/gxemul -E testmips -C R3000 -M64 elf-file运行 (其中elf-file是你编译生成的 vmlinux文件的路径)。
这一部分涉及到一点汇编的知识,请各位读者自行学习。
补全boot/start.S
重新make,并执行/OSLAB/gxemul -E testmips -C R3000 -M64 elf-file命令
2.5Exercise 1.5 阅读相关代码和下面对于函数规格的说明,补全 lib/print.c中 lp_Print()函数中缺失的部分来实现字符输出。
参考实验手册
补全lp-Prin()函数
重新make:
所有试验完成。