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:
所有試驗完成。