2018-2019-1 20189218《Linux内核原理与分析》第五周作业
系統調用的三層機制
用戶態、內核態和中斷
- 用戶態。較低的執行級別,只能訪問一部分內存,只能執行一部分指令。
- 內核態。高級執行級別,可以訪問任意物理內存,可以執行特權指令。
- 中斷。系統從用戶態進入內核態的主要方式。有硬件中斷和軟中斷。系統調用就是通過軟中斷進入內核態。
上下文切換
用戶態切換到內核態時,就要把用戶態寄存器上下文保存起來,同時要把內核態寄存器的值放到當前cpu中。int指令出發中斷機制會在堆棧上保存一些寄存器的值,會保存(SAVE_ALL)用戶態棧頂的值,當時的狀態字(flag),當時的CS:EIP的值。同時會將內核態的這些寄存器的值加載到cpu。其中內核態CS:EIP指向中斷處理程序的入口,如果是系統調用則指向system_call,當中斷結束后執行restore_all和INTERRUPT_RETURN。
API和系統調用
API就是系統調用的庫函數,是一個函數定義。系統調用是通過軟中斷向內核發出了中斷請求,int指令的執行就會觸發一個中斷請求,一個API可能只對應一個系統調用,也可能由多個系統調用實現。
Linux中通過int $0x80來觸發系統調用的執行,內核給每個系統調用一個編號,即系統調用號來指明是哪個系統調用,通過EAX寄存器傳遞。
無參數系統調用
依次通過c語言和內嵌匯編的c語言實現time()函數中封裝的系統調用。
time.c
課本上給出的time.c在編譯時遇到如下問題:
查看struct tm發現應該是mday:
修改后代碼如下:
修改后順利運行:
內嵌匯編的代碼運行順利:
自選系統調用access
其實沒什么大區別,C語言代碼及運行結果如圖:
內嵌匯編的代碼及運行結果如圖,比c語言代碼有所簡化:
帶兩個參數的系統調用
同樣運行順利,代碼如下:
通用庫函數syscall
新增的沒有被封裝好的系統調用可以通過syscall(系統調用號,參數表)實現,實際上比前兩種方式舒服很多。
于是我們需要知道系統調用對應的系統調用號,在編譯器中通過查看syscall.h中引用的unistd.h文件可以查看系統定義的系統調用號表。
至于為什么unistd.h中的宏定義的變量名和我們使用的不一樣,是因為在bits/syscall.h中又進行了一次宏定義:
這樣應該更有益于程序的可讀性和不同版本的兼容性(兼容性是官方的解釋,但我現在對不同版本之間的兼容不報什么希望)。
感想
在查看系統調用號表時,實際上系統中有大量的unistd.h,包括i386、x86_64安裝過的mykernel和Linuxkernel以及許多不知道來源的。通常是在/usr/include/asm目錄下,但在我的電腦上甚至沒有asm這個目錄。還好編譯器中鏈接到的文件是在搜索目錄中的,所以能比較快的找到需要的頭文件。
之前在編程中要用到系統中的命令都是由system(command)實現,現在想來這應該是通過shell的封裝來調用的系統函數,效率應該比直接在程序中進行系統調用低不少。
一個小問題
這章之后對Linux系統的層次似乎多了些理解。按照我的理解,內核處于最底層,c語言中的系統調用和shell中的內建命令都是通過調用內核中的函數實現,是對內核中的函數的不同的封裝。C語言中syscall()是直接調用內核中的函數,而C語言中的system()函數則是通過調用shell間接的調用內核中的函數,所以命令可以和終端中的寫法保持一致,傳參也是直接傳字符串。希望這么理解是對的,在以后的實踐中去檢驗。
轉載于:https://www.cnblogs.com/thechosenone95/p/9932535.html
總結
以上是生活随笔為你收集整理的2018-2019-1 20189218《Linux内核原理与分析》第五周作业的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AVS 通信模块之HTTP2Transp
- 下一篇: zanePerfor 一款完整,高性能,