C程序函數(shù)調(diào)用&系統(tǒng)調(diào)用
理解程序的執(zhí)行
我們要知道CPU可以自由地訪問寄存器、內(nèi)存。另外,程序是由操作系統(tǒng)執(zhí)行的,所以操作系統(tǒng)能夠控制程序的所有執(zhí)行情況,限制程序的行為。
程序地執(zhí)行過(guò)程:
- 程序是一個(gè)二進(jìn)制文件,包含程序的代碼指令、代碼中的文本信息等(參考C語(yǔ)言的程序的各種段)
- 執(zhí)行一個(gè)程序后,會(huì)將這個(gè)二進(jìn)制加載到內(nèi)存中,那么這個(gè)程序的代碼(想象成各種匯編指令)也就記載道了內(nèi)存中
- CPU執(zhí)行程序時(shí)從固定的位置main處開始執(zhí)行(eip寄存器指向這里),逐條語(yǔ)句讀取執(zhí)行(這是CPU自帶的功能)
- 語(yǔ)句可能發(fā)生跳轉(zhuǎn)(eip切換到其他匯編指令出)
- 語(yǔ)句可能會(huì)操作棧(其實(shí)就是往一塊特殊地內(nèi)存空間寫入數(shù)據(jù)、讀出數(shù)據(jù),CPU有相關(guān)的指令pop push解決這個(gè)問題)
- 程序可能會(huì)執(zhí)行系統(tǒng)調(diào)用(操作系統(tǒng)賦予的能力,例如讀寫文件,網(wǎng)絡(luò)通信等)?,F(xiàn)代操作系統(tǒng)將這些能力都放到了內(nèi)核態(tài)來(lái)執(zhí)行了,即只有內(nèi)核代碼才能做實(shí)際的讀寫文件操作,普通用戶程序只能通過(guò)系統(tǒng)調(diào)用來(lái)執(zhí)行這些能力。
- 所以執(zhí)行系統(tǒng)調(diào)用后,cpu就會(huì)相應(yīng)地跳轉(zhuǎn)到系統(tǒng)調(diào)用地入口處(這個(gè)系統(tǒng)調(diào)用的入口也時(shí)固定的,對(duì)應(yīng)的是內(nèi)核中的一段C代碼
- 內(nèi)核的系統(tǒng)調(diào)用入口函數(shù),根據(jù)系統(tǒng)調(diào)用號(hào)(對(duì)每個(gè)系統(tǒng)調(diào)用的標(biāo)識(shí)),找到相應(yīng)的處理函數(shù)執(zhí)行(其實(shí)也是執(zhí)行call函數(shù))
- 系統(tǒng)調(diào)用處理完后,繼續(xù)返回到用戶自己的程序代碼處執(zhí)行(所以,在執(zhí)行系統(tǒng)調(diào)用前需要把用戶代碼執(zhí)行的位置記錄下來(lái),并且在系統(tǒng)調(diào)用結(jié)束后自動(dòng)設(shè)置eip指向這個(gè)地方)
函數(shù)調(diào)用
C語(yǔ)言函數(shù)調(diào)用關(guān)鍵
c語(yǔ)言函數(shù)調(diào)用的幾個(gè)關(guān)鍵點(diǎn)在于:
- 保護(hù)調(diào)用者的上下文(寄存器、棧指針(ebp,esp)信息)
- 將傳入?yún)?shù)通過(guò)esi、edi等放到被寄存器中、或者push到棧中(當(dāng)參數(shù)比較多時(shí))
- 執(zhí)行call調(diào)用函數(shù),call的副作用是將eip壓入到棧中
- 將計(jì)算的返回值放到eax中
- pop出ebp、esp
- 執(zhí)行ret,將eip從棧中pop出來(lái),然后指令繼續(xù)執(zhí)行重新回到調(diào)用者上下文(將esp指向調(diào)用者調(diào)用函數(shù)后的語(yǔ)句)
系統(tǒng)調(diào)用
- syscall sysenter sysret
- int 0x80
在 x86-64 架構(gòu)上,當(dāng)應(yīng)用程序需要執(zhí)行系統(tǒng)調(diào)用時(shí),CPU 會(huì)從用戶態(tài)切換到內(nèi)核態(tài),經(jīng)歷以下過(guò)程:
- 用戶態(tài)程序執(zhí)行
syscall
指令:- 用戶態(tài)程序通過(guò)執(zhí)行
syscall
指令來(lái)觸發(fā)系統(tǒng)調(diào)用請(qǐng)求。
- 用戶態(tài)程序通過(guò)執(zhí)行
- CPU 切換到內(nèi)核態(tài):
syscall
指令會(huì)引發(fā)一個(gè)特殊的異常,導(dǎo)致 CPU 從當(dāng)前的用戶態(tài)特權(quán)級(jí)切換到內(nèi)核態(tài)的更高特權(quán)級(jí)。- 這個(gè)過(guò)程會(huì)自動(dòng)保存用戶態(tài)的部分寄存器狀態(tài),如
rip
、rflags
等,并將控制權(quán)轉(zhuǎn)交給內(nèi)核。
- 內(nèi)核處理系統(tǒng)調(diào)用:
- 內(nèi)核接管控制權(quán)后,會(huì)根據(jù)系統(tǒng)調(diào)用號(hào)找到對(duì)應(yīng)的系統(tǒng)調(diào)用處理函數(shù),并執(zhí)行相應(yīng)的操作。
- 內(nèi)核執(zhí)行完成后,會(huì)將結(jié)果返回給用戶態(tài)程序。
- 從內(nèi)核態(tài)切換回用戶態(tài):
- 內(nèi)核執(zhí)行完系統(tǒng)調(diào)用處理后,會(huì)通過(guò)
sysret
指令從內(nèi)核態(tài)切換回用戶態(tài)。 sysret
指令會(huì)自動(dòng)恢復(fù)之前保存的用戶態(tài)寄存器狀態(tài),并將控制權(quán)轉(zhuǎn)回給用戶態(tài)程序。
- 內(nèi)核執(zhí)行完系統(tǒng)調(diào)用處理后,會(huì)通過(guò)
整個(gè)切換過(guò)程由硬件和操作系統(tǒng)內(nèi)核共同完成,應(yīng)用程序感知不到這個(gè)切換過(guò)程。這種基于硬件支持的用戶態(tài) - 內(nèi)核態(tài)切換機(jī)制,能夠大幅降低系統(tǒng)調(diào)用的開銷,提高操作系統(tǒng)的整體性能。
需要注意的是,除了 syscall/sysret
指令,Intel 的 x86-64 架構(gòu)也支持使用 int 0x80
軟中斷來(lái)執(zhí)行系統(tǒng)調(diào)用,不過(guò) syscall/sysret
方式通常更加高效。
cpu的特權(quán)級(jí)別(privilege level )
chatgpt告訴我們:Linux 系統(tǒng)通過(guò)以下幾種方式來(lái)實(shí)現(xiàn)當(dāng)前特權(quán)級(jí)別的切換:
- 系統(tǒng)調(diào)用:
- 用戶態(tài)應(yīng)用程序通過(guò)系統(tǒng)調(diào)用機(jī)制從 Ring 3 切換到 Ring 0 內(nèi)核態(tài)。
- 應(yīng)用程序執(zhí)行
int 0x80
或syscall
指令觸發(fā)軟中斷,CPU 切換到 Ring 0 執(zhí)行內(nèi)核代碼。 - 內(nèi)核處理完成后,通過(guò)
iret
或sysret
指令返回到用戶態(tài)。
- 中斷/異常處理:
- 當(dāng) CPU 遇到硬件中斷或軟件異常時(shí), 會(huì)自動(dòng)從當(dāng)前特權(quán)級(jí)切換到 Ring 0 內(nèi)核態(tài)。
- 內(nèi)核處理完中斷/異常后,通過(guò)
iret
指令返回到之前的特權(quán)級(jí)別。
- 特權(quán)級(jí)切換指令:
- x86 架構(gòu)提供了一些用于特權(quán)級(jí)切換的指令,如
call gate
、task gate
等。 - 這些指令可以在不同特權(quán)級(jí)之間跳轉(zhuǎn),并自動(dòng)完成上下文切換。
- x86 架構(gòu)提供了一些用于特權(quán)級(jí)切換的指令,如
- 進(jìn)程切換:
- 當(dāng)內(nèi)核需要切換進(jìn)程時(shí),會(huì)切換進(jìn)程的特權(quán)級(jí)別。
- 內(nèi)核將新進(jìn)程的特權(quán)級(jí)別設(shè)置為 Ring 3,并通過(guò)
iret
指令返回到用戶態(tài)。
在 Linux 中,大多數(shù)情況下都是通過(guò)系統(tǒng)調(diào)用和中斷/異常處理來(lái)實(shí)現(xiàn)特權(quán)級(jí)切換。內(nèi)核代碼運(yùn)行在 Ring 0 級(jí)別,用戶態(tài)應(yīng)用程序運(yùn)行在 Ring 3 級(jí)別。當(dāng)應(yīng)用程序需要訪問受保護(hù)的系統(tǒng)資源時(shí),會(huì)通過(guò)系統(tǒng)調(diào)用陷入內(nèi)核態(tài),由內(nèi)核代碼執(zhí)行相應(yīng)的操作。中斷和異常處理也會(huì)觸發(fā)內(nèi)核態(tài)的切換,內(nèi)核負(fù)責(zé)處理各種硬件事件??傊?Linux 系統(tǒng)利用 CPU 硬件提供的特權(quán)級(jí)機(jī)制,通過(guò)系統(tǒng)調(diào)用、中斷/異常處理、特權(quán)級(jí)切換指令等方式,實(shí)現(xiàn)了內(nèi)核態(tài)和用戶態(tài)之間的特權(quán)級(jí)切換,保證了系統(tǒng)的安全和穩(wěn)定性。
Ring 0和Ring 3也有其他區(qū)別,例如Ring 0 程序可以執(zhí)行所有的 CPU 指令集,包括特權(quán)指令。Ring 3 程序只能執(zhí)行非特權(quán)指令集,無(wú)法直接執(zhí)行特權(quán)級(jí)別的指令。
到此這篇關(guān)于C程序函數(shù)調(diào)用&系統(tǒng)調(diào)用的文章就介紹到這了,更多相關(guān)C程序函數(shù)調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS Code C/C++環(huán)境配置教程(無(wú)法打開源文件“xxxxxx.h”或者檢測(cè)到 #include 錯(cuò)誤,請(qǐng)更新in
這篇文章主要介紹了VS Code C/C++環(huán)境配置教程(無(wú)法打開源文件“xxxxxx.h” 或者 檢測(cè)到 #include 錯(cuò)誤。請(qǐng)更新includePath) (POSIX API),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08C語(yǔ)言實(shí)現(xiàn)的循環(huán)單鏈表功能示例
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)的循環(huán)單鏈表功能,結(jié)合實(shí)例形式分析了基于C語(yǔ)言實(shí)現(xiàn)的循環(huán)單鏈表定義、創(chuàng)建、添加、刪除、打印、排序等相關(guān)操作技巧,需要的朋友可以參考下2018-04-04C++日期與時(shí)間 chrono庫(kù)介紹及使用教程
chrono庫(kù)是C++11中的一個(gè)標(biāo)準(zhǔn)庫(kù),它提供了一系列與時(shí)間相關(guān)的類和函數(shù),用于表示和處理時(shí)間間隔,時(shí)鐘和時(shí)間點(diǎn),C++20新增Calendar,這篇文章主要介紹了C++日期與時(shí)間 chrono庫(kù)介紹及使用,需要的朋友可以參考下2023-12-12Java?C++題解leetcode1598文件夾操作日志搜集器
這篇文章主要為大家介紹了Java?C++題解leetcode1598文件夾操作日志搜集器示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09C++實(shí)現(xiàn)單例模式的自動(dòng)釋放
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)單例模式的自動(dòng)釋放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06