BUAA_OS_Lab1實驗報告


思考題


Thinking1.1

也許你會發現我們的 readelf 程序是不能解析之前生成的內核文件 (內核文件是可執行文件) 的,而我們剛才介紹的工具 readelf 則可以解析,這是為什么呢?(提示:嘗試使用 readelf -h,觀察不同)

當我使用./readelf vmlinux命令時彈出“段錯誤 (核心已轉儲)”信息,我嘗試使用readelf -h *命令觀察不同的ELF文件的信息,發現是數據編碼格式導致的問題。觀察Magic[5]可以看到vmlinux是MSB編碼,而其余可以解析的文件則是LSB,導致讀取信息時發生錯誤,例如0x01020304被讀成了0x04030201.在lab1課上測試中我完成了trans()函數完成了對vmlinux文件的解讀。

(vmlinux)Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Thinking1.2

內核入口在什么地方?main 函數在什么地方?我們是怎么讓內核進入到想要的 main 函數的呢?又是怎么進行跨文件調用函數的呢?

內核入口是_start函數在boot/start.Smain函數在init/main.c,內核啟動先執行_start入口函數,然后從這個函數跳轉到main函數,從start.S文件中jal main命令可以看出。這樣內核啟動的入口地址就可以固定下來,只需要傳遞main函數的地址就可以實現不同位置的main函數的調用。

跨文件調用函數:通過include頭文件的方式。將需要函數寫入.h文件,然后其他文件需要使用這些函數時include相應頭文件即可。

實驗難點圖示


ELF文件的結構——ELF文件的解析

ELF文件在編譯鏈接和運行兩種視角下的結構,指導書已經解釋地很明確了,這里就不贅述了。在實驗過程中關鍵要理解ELF文件中的結構體,事實上ELF文件的解讀是我們要用正確的結構體變量在正確的位置找到其屬性,這里需要明確一下這些結構體之間的層次關系,以本次聯系用到的Section header為例,我繪制了不同層次結構的關系:

要注意選擇正確的結構體指針,不同的結構體指針可能指向同一個地址值,但是其含義不同,其顆粒度也不同(p++運算的結果不同)

在對指針的地址值進行運算的時候要注意到指針顆粒度的問題,練習中要求我們找到節頭表的首地址,由於e_shoff是以字節(8位)為單位存儲的,所以在計算地址的時候我們要考慮到這一點,所以使用unsigned char*類型指針進行地址的運算,得到節頭表的地址后,我們要將節頭表按照節頭數組的形式訪問,所以此時我們訪問的單位是節頭結構體,所以我們要將地址的指針類型進行轉換。

內核地址與Linker Script

mmp.h文件中給出了結構圖,在這個圖中可以找到kernel部分的存儲空間,所以我們的任務就是要重定位到指定的位置

第一步我們要設置靜態確定的內存空間。通過Linker Script的SECTIONS部分將data、text、bss段的地址重定位。

第二部我們要考慮到動態運行時的內存空間,我們要事先確定這部分空間的范圍。由於空間的上邊界是棧,我們要在_start進入main函數時將sp指針指向stack的地址,於是內存空間的上邊界也完成了重定位。

printf與字符識別狀態機

第一個難點是字符串的解析,由於題目要求比較簡單,用狀態機分析清晰易懂。

定義狀態

0:start 已識別到‘%’,開始解析格式字符串

1:flags 解析到'0''-',開始解析flags部分

2:width 解析width

3:start_prec 解析到'.',開始准備解析prec

4:prec 解析prec

5:length 解析length

6:switch 即將解析specifier,進入switch語句段

如下是狀態轉移表S,其中s(i,j)表示狀態 i 到狀態 j 的轉移條件。

state 0 1 2 3 4 5 6
0 '0'|'-' 1~9 '.' 'l' else
1 0~9 '.' 'l' else
2 0~9 '.' 'l' else
3 0~9 'l' else
4 0~9 'l' else
5 No condition
6

第二個難點是利用輔助函數實現不同specifier下的輸出,這里考驗我們閱讀別人代碼的能力。此處d(D)情況下使用PrintNum()函數時出現了bug,閱讀了PrintNum()函數后發現傳遞的num應當是絕對值,數字的正負由negFlag表示。所以在之后的lab中,除了自己寫代碼外,更要注重閱讀源碼。

體會與感想


由於lab0熟悉了linux操作環境,git版本管理工具,本次試驗中可以說是相比lab0得心應手了,誤刪了重要文件后通過版本回退拯救了自己,通過tmux、vim內置命令、grep、gcc等命令是我能夠非常舒服地寫c代碼與調試,工程技巧和經驗積累量一些,並且能夠自己寫一些簡單的Makefile、*.sh幫助自己,對Makefile中依賴這個概念有了更深入的了解。

整個過程依舊感到很痛苦,雖然大體明白要實現的目的與過程,但是對其中各種細節模模糊糊讓我感覺很難下手,例如printf中設計出了自動機的算法,但是對其中的各種各樣的指針,宏函數、輔助輸出函數、可變長參數等新事物感到雲里霧里,甚至不知道自己要用什么怎么用,所以發呆了很長時間。

雖然做完了練習題並得到了分數,但是依舊對整個過程感到很模糊。內核的啟動過程,交叉編譯等過程感到迷惑,各種術語不清楚,對其中各種目錄下奇奇怪怪的文件不知道什么用途。但是實驗結束后可以看出有很多其實只是要大致了解即可,我應當培養的能力是從眾多文件中知道哪些是我需要用到的,然后再研究這個范圍內的細節,當然也是要慢慢來。

lab1反復閱讀指導書,總算弄清楚了ELF文件格式,對它有了一個形象化的認知。其中各種結構體的引用讓我惡補了一番c語言指針的知識,也算是有所收獲,最終做出了printf練習,有一定的成就感。

指導書反饋


建議增加一部分對專業術語、概念的講解,網上能夠查到的很多資料對初學者來看都是用一些專業名詞解釋另一些專業名詞,讓初學者很難找到學習的入口點,如果指導書對概念加一些解釋會更好。

有些概念的漢語名稱可以統一,或者一律用英文,比如program(segment) header table、section header table。

思考題和練習能否向討論區一樣單獨開辟一個頁面,方便自己查找自己是否有遺漏。

殘留難點


Makefile的更多強大的功能還有待我解鎖

學習如何在linux環境下搭建自動測評


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM