日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

彻底搞懂系统调用

發(fā)布時(shí)間:2023/12/20 windows 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 彻底搞懂系统调用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在應(yīng)用程序開發(fā)過程中經(jīng)常會進(jìn)行IO設(shè)備的操作,比如磁盤的讀寫,網(wǎng)卡的讀寫,鍵盤,鼠標(biāo)的讀入等,大多數(shù)應(yīng)用開發(fā)人員使用高級語言進(jìn)行開發(fā),例如C,C++,java,python等,這些高級語言都提供了標(biāo)準(zhǔn)庫或者API去操作IO設(shè)備,不過標(biāo)準(zhǔn)庫或者API最終還是通過系統(tǒng)調(diào)用來實(shí)現(xiàn)操作IO設(shè)備的,系統(tǒng)調(diào)用是操作系統(tǒng)提供的,它是操作系統(tǒng)內(nèi)核的一部分。

系統(tǒng)調(diào)用封裝了對硬件操作的所有細(xì)節(jié),而標(biāo)準(zhǔn)庫或者SDK又在系統(tǒng)調(diào)用的基礎(chǔ)上做了高度抽象的封裝和優(yōu)化,因此使得應(yīng)用程序開發(fā)人員的日子好過多了,開發(fā)效率也提高了不少。

1

本篇文章主要闡述以下兩部分:

1.什么是系統(tǒng)調(diào)用?

2.系統(tǒng)調(diào)用的實(shí)現(xiàn)?

主要以Linux 操作系統(tǒng)和IA-32處理器舉例,高級語言以C語言為例,同時(shí)也會摻雜一些其它操作系統(tǒng)和處理器。

什么是系統(tǒng)調(diào)用?

對于現(xiàn)代的操作系統(tǒng)來說,應(yīng)用程序運(yùn)行的時(shí)候是沒有權(quán)限去訪問系統(tǒng)資源的,操作系統(tǒng)為了防止各類應(yīng)用程序可能會破壞系統(tǒng)資源,對系統(tǒng)資源做了保護(hù),阻止應(yīng)用程序直接去訪問這些資源,而應(yīng)用程序又有訪問這些系統(tǒng)資源的需求,因此操作系統(tǒng)提供了系統(tǒng)調(diào)用,讓所有的應(yīng)用程序統(tǒng)一通過系統(tǒng)調(diào)用來訪問系統(tǒng)資源,這里所說的系統(tǒng)資源包括文件,網(wǎng)絡(luò) ,內(nèi)存,各類IO設(shè)備等。

應(yīng)用程序可以進(jìn)行系統(tǒng)調(diào)用,也可以調(diào)用標(biāo)準(zhǔn)庫或者API,一個(gè)系統(tǒng)調(diào)用的內(nèi)部有很多的步驟,比如需要進(jìn)行用戶態(tài)模式到內(nèi)核態(tài)模式的互相切換。

這里簡單介紹下模式切換,我們知道一個(gè)完整的應(yīng)用程序分為兩部分,一部分是應(yīng)用程序的代碼和數(shù)據(jù),另一部分是內(nèi)核的代碼和數(shù)據(jù),切換模式就是這兩部分的分水嶺,意味著處理器進(jìn)入了一個(gè)不同的模式,不同的模式就是不同的世界,不同的世界就有不同的權(quán)限,而內(nèi)核態(tài)模式就是王者,可以掌握所有的資源,用戶態(tài)模式只能掌握自己的一畝三分地。

正如上面所說,系統(tǒng)調(diào)用需要進(jìn)行模式切換,而每個(gè)完整的應(yīng)用程序都有兩個(gè)棧,一個(gè)用戶棧,一個(gè)內(nèi)核棧,這兩個(gè)棧是獨(dú)立的,用戶棧在用戶空間,內(nèi)核棧在內(nèi)核空間,因此切換模式時(shí),棧也得切換。

因此我們可以將系統(tǒng)調(diào)用的執(zhí)行步驟分為三步:1.執(zhí)行前的準(zhǔn)備工作。2.執(zhí)行處理程序(處理函數(shù))。3.執(zhí)行后的善后工作,當(dāng)然內(nèi)核模式切換和棧切換就是1和3的工作了,這里的三步都是在內(nèi)核模式下執(zhí)行的,如下圖所示

應(yīng)用程序直接系統(tǒng)調(diào)用步驟

從上圖得知,執(zhí)行一個(gè)系統(tǒng)調(diào)用很復(fù)雜,需要干很多的活,Linux的編譯器提供了很多共享庫(so文件)來提供系統(tǒng)調(diào)用,例如Linux的glibc庫就提供了文件操作相關(guān)的系統(tǒng)調(diào)用,例如下面的代碼:

int read(int fd,void *buf,int count);//讀文件數(shù)據(jù) int write(int fd,const void *buf,int couint);//寫文件數(shù)據(jù) int open(const char * pathname,int flags,mode_t mode);//打開文件

上面的代碼只是glibc庫中幾個(gè)比較有代表性的例子,linux操作系統(tǒng)提供了幾百個(gè)系統(tǒng)調(diào)用,這些系統(tǒng)調(diào)用分散在各個(gè)共享庫中,這里就不再闡述。

Windows操作系統(tǒng)提供了API,簡稱Windows API或者SDK,它不是系統(tǒng)調(diào)用而是對系統(tǒng)調(diào)用做了二次封裝,這些API是由各類DLL(動態(tài)鏈接庫)提供的,開發(fā)人員導(dǎo)入這些DLL就可以通過Windows API來開發(fā)Windows應(yīng)用程序,因此Widows應(yīng)用程序執(zhí)行系統(tǒng)調(diào)用的步驟就變成了如下圖所示

Windows應(yīng)用程序系統(tǒng)調(diào)用步驟

正如上文所述,每個(gè)操作系統(tǒng)都提供它各自的系統(tǒng)調(diào)用,那么寫一段C代碼怎樣能做到跨操作系統(tǒng)呢?答案是C語言標(biāo)準(zhǔn)庫,C語言標(biāo)準(zhǔn)庫的目的就是讓開發(fā)人員寫一段C代碼,這些C代碼使用的是C標(biāo)準(zhǔn)庫,那么這段代碼不需要進(jìn)行任何修改就可以跨操作系統(tǒng),前提是經(jīng)過不同操作系統(tǒng)編譯器的編譯,C標(biāo)準(zhǔn)庫的調(diào)用關(guān)系如下圖

C標(biāo)準(zhǔn)庫

由上圖得知,Linux通過共享庫直接提供系統(tǒng)調(diào)用,而Windows則通過Windows API間接進(jìn)行提供系統(tǒng)調(diào)用,中間增加了一個(gè)C標(biāo)準(zhǔn)庫,它將不同操作系統(tǒng)之間系統(tǒng)調(diào)用標(biāo)準(zhǔn)化,做了二次封裝,簡化了系統(tǒng)調(diào)用的復(fù)雜度,提供給應(yīng)用程序。

標(biāo)準(zhǔn)庫也有它的缺點(diǎn),缺點(diǎn)就是只能取各個(gè)操作系統(tǒng)系統(tǒng)調(diào)用的交集,這意味著只有操作系統(tǒng)都有的功能才能納入到標(biāo)準(zhǔn)庫,然后有的時(shí)候,需要一些操作系統(tǒng)專有的功能時(shí),還得直接進(jìn)行系統(tǒng)調(diào)用或者調(diào)用API,這個(gè)就會出現(xiàn)跨系統(tǒng)的問題。

對于用標(biāo)準(zhǔn)庫開發(fā)的應(yīng)用程序,它的系統(tǒng)調(diào)用步驟可以總結(jié)如下圖

C標(biāo)準(zhǔn)庫系統(tǒng)調(diào)用

好了,【什么是系統(tǒng)調(diào)用】的話題介紹到這里了,下面來看看系統(tǒng)調(diào)用具體是怎么實(shí)現(xiàn)的。

2

系統(tǒng)調(diào)用的實(shí)現(xiàn)?

上個(gè)環(huán)節(jié)闡述的是【什么是系統(tǒng)調(diào)用】以及系統(tǒng)調(diào)用的大致步驟,這個(gè)環(huán)節(jié)將以Linux操作系統(tǒng)為例來闡述系統(tǒng)調(diào)用的實(shí)現(xiàn)原理和細(xì)節(jié),當(dāng)然其它操作系統(tǒng)系統(tǒng)調(diào)用的實(shí)現(xiàn)原理比較相似,可以舉一反三。

主流的操作系統(tǒng)如Linux和Windows是通過中斷來實(shí)現(xiàn)系統(tǒng)調(diào)用的。

以操作系統(tǒng)Linux(2.5以前),處理器為Inter IA-32為例,看看fork這個(gè)系統(tǒng)調(diào)用是怎么實(shí)現(xiàn)的,其它的Linux系統(tǒng)調(diào)用類似,整體過程如下圖

Linux系統(tǒng)調(diào)用過程

上圖為系統(tǒng)調(diào)用涉及到的9個(gè)步驟,我們逐個(gè)看起

1.應(yīng)用程序調(diào)用linux庫提供的fork函數(shù),發(fā)起一個(gè)fork系統(tǒng)調(diào)用,這個(gè)系統(tǒng)調(diào)用的目的是創(chuàng)建一個(gè)子進(jìn)程,這個(gè)子進(jìn)程拷貝一份父進(jìn)程的虛擬進(jìn)程空間。

2.fork函數(shù)的第一步就是將2放入寄存器eax,每個(gè)系統(tǒng)調(diào)用都有一個(gè)編號,2就是fork系統(tǒng)調(diào)用的編號,eax是默認(rèn)用于傳遞系統(tǒng)調(diào)用編號的寄存器。

如果系統(tǒng)調(diào)用有參數(shù),則將參數(shù)傳入到如下的寄存器EBX,ECX,EDX,ESI,EDI,EBP,可以看出系統(tǒng)調(diào)用最多支持6個(gè)參數(shù),fork系統(tǒng)調(diào)用沒有參數(shù)。

fork函數(shù)的第二步就是執(zhí)行中斷指令int 0x80,中斷指令int用于發(fā)送中斷信號給處理器,0x80為中斷向量號,這個(gè)向量號是系統(tǒng)調(diào)用中斷處理程序?qū)S谩?/p>

int指令同時(shí)也會將模式從用戶態(tài)切換到內(nèi)核態(tài),用戶棧切換到內(nèi)核棧,同時(shí)會將當(dāng)前被中斷的應(yīng)用程序,中斷時(shí)的寄存器內(nèi)容入棧(SS,ESP,EFLAGS,CS,EIP),這里的入棧指的是入內(nèi)核棧(每一個(gè)應(yīng)用程序都一個(gè)用戶棧和內(nèi)核棧)。

整體來看,2步驟的匯編代碼如下:

push EAX,2;//設(shè)置fork系統(tǒng)調(diào)用的系統(tǒng)調(diào)用編號 mov EBX,arg1;//可選,參數(shù)1 mov ECX,arg1;//可選,參數(shù)2 mov EDX,arg1;//可選,參數(shù)3 mov ESI,arg1;//可選,參數(shù)4 mov EDI,arg1;//可選,參數(shù)5 mov EBP,arg1;//可選,參數(shù)6 int 0x80;//發(fā)送系統(tǒng)調(diào)用中斷信號

3.處理器執(zhí)行完當(dāng)前的指令后,會檢查處理器的中斷引腳,發(fā)現(xiàn)有中斷信號,然后檢查狀態(tài)寄存器(EFLAGS),發(fā)現(xiàn)中斷屏蔽IF標(biāo)志是打開的(系統(tǒng)調(diào)用中斷信號不會被屏蔽),處理器根據(jù)中斷信號,分析出中斷向量號,然后根據(jù)中斷向量號去查找中斷描述符表,找到了該中斷向量號對應(yīng)的中斷處理程序。

4.操作系統(tǒng)跳轉(zhuǎn)到中斷處理程序,然后開始執(zhí)行中斷處理程序,0x80對應(yīng)的中斷處理程序是系統(tǒng)調(diào)用中斷處理程序(system_call)。

該中斷處理程序首先會將EAX,EBX,ECX,EDX,ESI,EDI,EBP這幾個(gè)寄存器入棧,之所以入棧,就是為了防止后續(xù)的工作覆蓋這些寄存器,核心匯編指令如下:

push EAX; push EBX; push ECX; push EDX; push ESI; push EDI; push EBP;

5.系統(tǒng)調(diào)用中斷處理程序緊接著根據(jù)系統(tǒng)調(diào)用號(這里就是fork系統(tǒng)調(diào)用號即2),去系統(tǒng)調(diào)用表進(jìn)行查找,可以找到該系統(tǒng)調(diào)用號對應(yīng)的處理程序(也可以叫處理函數(shù)),Linux操作系統(tǒng)的系統(tǒng)處理函數(shù)一般以sys開頭,fork的系統(tǒng)處理函數(shù)就是sys_fork。

6.找到了系統(tǒng)處理函數(shù)后,開始執(zhí)行該函數(shù),處理函數(shù)可以從內(nèi)核棧中獲取函數(shù)的參數(shù),函數(shù)執(zhí)行完成后,函數(shù)的返回值,默認(rèn)采用EAX寄存器進(jìn)行返回。

7~8.系統(tǒng)處理函數(shù)執(zhí)行完成后,回到了系統(tǒng)調(diào)用中斷處理程序,中斷處理程序執(zhí)行iret指令,iret指令負(fù)責(zé)從內(nèi)核態(tài)切換到用戶態(tài),將內(nèi)核態(tài)入棧的寄存器數(shù)據(jù)出棧到SS,ESP,EFLAGS,CS,EIP這幾個(gè)寄存器,然后跳轉(zhuǎn)到系統(tǒng)調(diào)用處。

9.系統(tǒng)調(diào)用fork返回到應(yīng)用程序。

3

Linux操作系統(tǒng)(2.5以前)的系統(tǒng)調(diào)用實(shí)現(xiàn)原理闡述完了,Windows操作系統(tǒng)的系統(tǒng)調(diào)用也采用類似的機(jī)制,另外要說的是,自從Linux(2.5)以上,處理器Inter 奔騰二代以后,為了提高系統(tǒng)調(diào)用的效率,Inter處理器提供了兩個(gè)指令來進(jìn)行系統(tǒng)調(diào)用的進(jìn)入和退出即sysenter和sysexit指令。

sysenter指令代替了int中斷指令發(fā)起系統(tǒng)調(diào)用,執(zhí)行這個(gè)指令后,會直接跳轉(zhuǎn)到一個(gè)系統(tǒng)調(diào)用的處理函數(shù)地址處,去執(zhí)行系統(tǒng)調(diào)用,這個(gè)處理函數(shù)的地址是存儲在一個(gè)指定的寄存器中,sysenter這個(gè)指令也負(fù)責(zé)模式的切換和應(yīng)用程序現(xiàn)場寄存器的備份,這一點(diǎn)同int一樣,處理函數(shù)參數(shù)的傳遞跟以前一樣,還是通過寄存器的方式傳遞,沒有變化。

sysexit指令代替了iret恢復(fù)指令,它負(fù)責(zé)模式切換和現(xiàn)場寄存器的恢復(fù),這一點(diǎn)同iret指令相似。

其它的操作系統(tǒng)例如Power PC,AMD的系統(tǒng)調(diào)用與Linux(2.5以上)類似,不同的是,它們采用不同的指令來進(jìn)行模式切換和寄存器備份,參數(shù)的傳遞也是采用寄存器的方式,只是寄存器個(gè)數(shù)和名稱不一樣罷了。

轉(zhuǎn)自:一口Linux 并做整理


推薦閱讀:

專輯|Linux文章匯總

專輯|程序人生

專輯|C語言

我的知識小密圈

關(guān)注公眾號,后臺回復(fù)「1024」獲取學(xué)習(xí)資料網(wǎng)盤鏈接。

歡迎點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā),在看,您的每一次鼓勵,我都將銘記于心~

總結(jié)

以上是生活随笔為你收集整理的彻底搞懂系统调用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。