從控制程式碼的概念再看分層設計

科技小能手發表於2017-11-12

幾個層次問題,首先實體記憶體和虛擬記憶體,作業系統管理實體記憶體,而使用者程式使用虛擬記憶體,作業系統呈現給使用者程式的是連續的虛擬記憶體但是不一定連續的實體記憶體,實體記憶體隨時在變化,但是對於使用者程式來說其虛擬記憶體地址是不變的;其次是指標和控制程式碼,作業系統為了向使用者空間提供若干臺虛擬機器並且又要管理一些所有程式需要的系統服務,必然不能將核心資料結構呈現給程式,但是程式確實可以使用這種資料,因此控制程式碼就出現了,控制程式碼其實是指標的指標,雖然它不是真正意義上的指標,由於作業系統管理的資料結構易變,並且處於高特權級,所以作業系統不能將之開放給使用者空間,使用者空間只能通過控制程式碼來呼叫系統服務,進入核心之後,核心會根據控制程式碼找到真正的核心資料結構,很多實現中控制程式碼就是核心中程式塊中一個表的索引欄位,因為虛擬機器是基於程式的,比如linux的task_struct中的開啟檔案表,在windows中的做法更是深刻,一切都是物件,因此每個物件都有控制程式碼,程式,執行緒本身,檔案,裝置,視窗,…都有控制程式碼,其程式塊中有一個控制程式碼表,每一個元素代表一個物件。正是因為windows的一切皆物件特性,其可以操作遠端程式,因為程式是一個物件,而物件有控制程式碼,有了控制程式碼就可以操作,win32API中很多介面都是基於控制程式碼的物件操作介面,在linux中似乎只有檔案體現為控制程式碼,也只有檔案是程式可以共享的,由於沒有別的控制程式碼,因此也就不能隨意操作別的物件。

控制程式碼隱藏了核心的管理細節,呈現給程式一個平滑的結構,實際上控制程式碼指向的真正的結構的地址是可以變化的,正如一個指標不變的情況下,其指向的資料可以變化,控制程式碼的作用有二:第一,隱藏不必要的操作,作為唯一介面由API只開放可用的安全操作;第二,類似實體記憶體和虛擬記憶體的關係,向使用者空間提供一個穩定的結構操作把手,將抽象從作業系統提升到程式。在作業系統中,抽象是基於檔案,裝置的,但是到了程式就統一都成了控制程式碼,體現了在控制程式碼指向的資料結構上的多路複用,按照分層原則,上層可以在下層提供的一個地址格式上多路複用,按照抽象的原則,越往上抽象程度越高,正如TCP和UDP可以複用一個IP地址一樣,多個程式的多個控制程式碼可以指向同一個核心資料結構。

控制程式碼是一個層次間通訊的通道,每一個程式虛擬機器都通過控制程式碼來使用共享的作業系統核心服務,但是這只是一類服務,程式虛擬機器並不是靠控制程式碼來使用作業系統的一切服務的,還有一類服務和作業系統一樣可以直接使用更底層的硬體機制,比如MMU。前面的一篇文章說過,作業系統給程式虛擬機器抽象兩類指令,一類是安全的指令,這類指令直接並且始終在cpu-記憶體之間執行,執行這類指令不需要經過作業系統層,還有一類指令不是僅僅在cpu執行,而是牽扯到了沒有提供多道程式環境的IO外設,對於這些資源的訪問,程式必須使用作業系統的服務而不能直接使用硬體機制了。對於MMU而言,其實也是一種和控制程式碼類似的抽象,多cpu上同時執行的不同程式可以同時訪問相同的虛擬地址(非共享記憶體),但是通過MMU轉換後的實體地址卻不同,這就是多路複用概念的引申。本質上講,MMU和作業系統核心是屬於同一層次的,只不過MMU是硬體固有的機制,而作業系統核心提供一些管理策略,對於控制程式碼而言,不同程式可以使用相同的控制程式碼,但是指向的實際核心資料結構卻不一定相同,因為控制程式碼和虛擬記憶體一樣,只在程式內部有意義,控制程式碼是程式中核心資料結構的索引,是為了使用者程式訪問核心資料結構而設計的,這種設計非常好,規定了使用者訪問核心資料結構只能在規則下進行,而規則就是以控制程式碼而引數的API的實現,其實就是系統呼叫的實現。

開放的控制程式碼越多,對作業系統設計的安全要求就越高,只要有控制程式碼,在得到控制程式碼表的情況下就很容易得到實際的資料,在windows上,系統漏洞很多由此而發,而linux上僅僅開放了開啟檔案這個控制程式碼,類似的漏洞也就很少了。為什麼?控制程式碼其實就是指標的指標,只不過這裡的指標的含義更加抽象了,不是一般意義上的指標

 本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1274130


相關文章