1. 程式人生 > >讀書筆記之應用程式與作業系統之間的關係——《作業系統之真相還原》

讀書筆記之應用程式與作業系統之間的關係——《作業系統之真相還原》

這個知識點很好的解釋了為什麼一些程式不能跨平臺使用,比如windows與linux之間的應用程式一般不能通用,底層庫不同,可執行程式的格式也不同,後面章節中作者也點明瞭這個問題。此問題可見知乎上的討論:主要的原因是格式不同API不同,前者更重要一些。http://www.zhihu.com/question/24369805,另外有個東西也可以瞭解下wine——Wine (“Wine Is Not an Emulator” 的遞迴縮寫)是一個能夠在多種 POSIX-compliant 作業系統(諸如 Linux,Mac OSX 及 BSD 等)上執行 Windows 應用的相容層。關於Wine的真正含義,有人對“Wine Is Not an Emulator”的說法表示質疑,認為”非模擬器“的解釋不過是一種娛樂性的說法,Wine的真實意思應當是是Windows Environment的縮寫,即WinE。

問題:應用程式是什麼,和作業系統是如何配合到一起的?

應用程式是軟體(似乎是廢話,別急,往後看),作業系統也是軟體。CPU會將它們一視同仁,甚至,CPU不知道自己在執行的程式是作業系統,還是一般應用軟體,CPU只知道去cs:ip暫存器中指向的記憶體取指令並執行,它不知道什麼是作業系統,也無需知道。

作業系統是人想出來的,為了讓自己管理計算機方便而創造出來的一套管理辦法。

應用程式要用某種語言編寫,而語言又是編譯器來提供的。其實根本就沒有什麼語言,有的只是編譯器。是編譯器決定怎樣解釋某種關鍵字及某種語法。語言只是編譯器和大家的約定,只要寫入這樣的程式碼,編譯器便將其翻譯成某種機器指令,翻譯成什麼樣取決於編譯器的行為,和語言無關,比如說C語言的printf函式,它的功能不是說一定要把字元列印到螢幕上,這要看編譯器對這種關鍵字的處理。

編譯器提供了一套庫函式,庫函式中又有封裝的系統呼叫,這樣的程式碼集合稱之為執行庫。C語言的執行庫稱為C執行庫,就是所謂的CRT(C Runtime Library)。

應用程式加上作業系統提供功能才算是完整的程式。由於有了作業系統的支援,一些現成的東西已經擺在那了,但這些是屬於作業系統的,不是應用程式的,所以咱們平時所寫的應用程式只是半成品,需要呼叫作業系統提供好的函式才能完整地做成一件事,而這個函式便是系統呼叫。

使用者態與核心態是對CPU來講的,是指CPU執行在使用者態(特權3級)還是核心態(特權0級),很多人誤以為是對使用者程序來講的。

使用者程序陷入核心態是指:由於內部或外部中斷髮生,當前程序被暫時終止執行,其上下文被核心的中斷程式儲存起來後,開始執行一段核心的程式碼。是核心的程式碼,不是使用者程式在核心的程式碼,使用者程式碼怎麼可能在核心中存在,所以“使用者態與核心態”是對CPU來說的。

當應用程式陷入核心後,它自己已經下CPU了,以後發生的事,應用程式完全不知道,它的上下文環境已經被儲存到自己的0特權級棧中了,那時在CPU上執行的程式已經是核心程式了。所以要清楚,核心程式碼並不是成了應用程式的核心化身,作業系統是獨立的部分,使用者程序永遠不會因為進入核心態而變身為作業系統了。

應用程式是通過系統呼叫來和作業系統配合完成某項功能的,有人可能會問:我寫應用程式時從來沒寫什麼系統呼叫的程式碼啊。這是因為你用到的標準庫幫你完成了這些事,庫中提供的函式其實都已經封裝好了系統呼叫,你需要跟下程式碼才會看到。其實也可以跨過標準庫直接執行系統呼叫,對於Linux系統來說,直接嵌入彙編程式碼“int 0x80”便可以直接執行系統呼叫,當然要提前設定好系統呼叫子功能號,該子功能號用暫存器eax儲存。

會不會有人又問,編譯器怎麼知道系統呼叫介面是什麼,哈哈,您想啊,下載編譯器時,是不是要選擇系統版本,編譯器在設計時也要知道自己將來執行在哪個系統平臺上,所以這都是和系統繫結好的,各個作業系統都有自己的系統呼叫號,編譯器廠商在程式碼中已經把宿主系統的系統呼叫號寫死了,沒什麼神奇的。

來看下什麼是使用者態與核心態:

使用者態(user mode)在計算機結構指兩項類似的概念。在CPU的設計中,使用者態指非特權狀態。在此狀態下,執行的程式碼被硬體限定,不能進行某些操作,比如寫入其他程序的儲存空間,以防止給作業系統帶來安全隱患。在作業系統的設計中,使用者態也類似,指非特權的執行狀態。核心禁止此狀態下的程式碼進行潛在危險的操作,比如寫入系統配置檔案、殺掉其他使用者的程序、重啟系統等。

只能受限的訪問記憶體, 且不允許訪問外圍裝置. 佔用CPU的能力被剝奪, CPU資源可以被其他程式獲取

核心態: CPU可以訪問記憶體所有資料, 包括外圍裝置, 例如硬碟, 網絡卡. CPU也可以將自己從一個程式切換到另一個程式。

為什麼會有使用者態和核心態?

由於需要限制不同的程式之間的訪問能力, 防止他們獲取別的程式的記憶體資料, 或者獲取外圍裝置的資料, 併發送到網路, CPU劃分出兩個許可權等級 -- 使用者態 和 核心態。

使用者態與核心態的切換

所有使用者程式都是執行在使用者態的, 但是有時候程式確實需要做一些核心態的事情, 例如從硬碟讀取資料, 或者從鍵盤獲取輸入等. 而唯一可以做這些事情的就是作業系統, 所以此時程式就需要先作業系統請求以程式的名義來執行這些操作.

這時需要一個這樣的機制: 使用者態程式切換到核心態, 但是不能控制在核心態中執行的指令

這種機制叫系統呼叫, 在CPU中的實現稱之為陷阱指令(Trap Instruction)

他們的工作流程如下:

  1. 使用者態程式將一些資料值放在暫存器中, 或者使用引數建立一個堆疊(stack frame), 以此表明需要作業系統提供的服務.
  2. 使用者態程式執行陷阱指令
  3. CPU切換到核心態, 並跳到位於記憶體指定位置的指令, 這些指令是作業系統的一部分, 他們具有記憶體保護, 不可被使用者態程式訪問
  4. 這些指令稱之為陷阱(trap)或者系統呼叫處理器(system call handler). 他們會讀取程式放入記憶體的資料引數, 並執行程式請求的服務
  5. 系統呼叫完成後, 作業系統會重置CPU為使用者態並返回系統呼叫的結果

前面提到了使用者程序陷入核心,這個好解釋,如果把軟體分層的話,最外圈是應用程式,裡面是作業系統,如圖0-1所示。

..\15-1444 圖\0001.tif

▲圖0-1 陷入核心

應用程式處於特權級3,作業系統核心處於特權級0。當用戶程式欲訪問系統資源時(無論是硬體,還是核心資料結構),它需要進行系統呼叫。這樣CPU便進入了核心態,也稱管態。看圖中凹下去的部分,是不是有陷進去的感覺,這就是“陷入核心”。