本實(shí)驗(yàn)選擇的系統(tǒng)調(diào)用號(hào)為34,在syscall_32.tbl中對(duì)應(yīng)如下項(xiàng):
41 i386 dup sys_dup
功能描述:
Dup() duplicates an existing object descriptor and returns its value to
the calling process (fildes2 = dup(fildes)). The argument fildes is a
small non-negative integer index in the per-process descriptor table.
The value must be less than the size of the table, which is returned by
getdtablesize(2). The new descriptor returned by the call is the lowest
numbered descriptor currently not in use by the process.
RETURN VALUES
Upon successful completion, the new file descriptor is returned. Otherwise, a value of -1 is returned and the global integer variable errno is set to indicate the error.
使用 libc 中提供的庫(kù)函數(shù)調(diào)用 的 C 代碼以及運(yùn)行結(jié)果如圖1所示:
其中,給 dup 函數(shù)傳遞的參數(shù)是1.
其中的程序成功通過(guò)新復(fù)制的 fild 進(jìn)行了寫入操作,在屏幕上輸出字符串.
直接在 C 代碼中使用內(nèi)聯(lián)匯編調(diào)用該系統(tǒng)調(diào)用的代碼及運(yùn)行結(jié)果如圖2所示:
從圖中可以看出對(duì) ebx 寄存器賦值為1,達(dá)到了傳遞參數(shù)的效果.同樣在屏幕上輸出了字符串.可知fild 復(fù)制成功.
匯編代碼調(diào)用系統(tǒng)調(diào)用的程序如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int new_fildes=0;
char *szTemp="test_dup\n";
asm volatile(
"mov $1,%%ebx\n\t" //傳遞參數(shù)
"mov $41,%%eax\n\t" //設(shè)置系統(tǒng)調(diào)用號(hào)
"int $0x80\n\t" //進(jìn)行軟中斷觸發(fā)
"mov %%eax,%0\n\t" //保存返回值
:"=m"(new_fildes)
);
printf("new fildes: %d\n",new_fildes);
write(new_fildes,szTemp,strlen(szTemp));
return 0;
}
系統(tǒng)調(diào)用的總?cè)肟谑?x80中斷,用 eax 寄存器存儲(chǔ)具體的中斷調(diào)用號(hào),本例中是41.除了系統(tǒng)調(diào)用號(hào)以外,大部分系統(tǒng)調(diào)用都還需要一些外部的參數(shù)輸人艺玲。所以涨醋,在發(fā)生異常的時(shí)候却特,應(yīng)該把這些參數(shù)從用戶空間傳給內(nèi)核扁位。最簡(jiǎn)單的辦法就是像傳遞系統(tǒng)調(diào)用號(hào)一樣把這些參數(shù)也存放在寄存器里羊瘩。在x86系統(tǒng)上岛心,ebx, ecx, edx, esi和edi按照順序存放前五個(gè)參數(shù)题画。需要六個(gè)或六個(gè)以上參數(shù)的情況不多見(jiàn)餐曼,此時(shí)压储,應(yīng)該用一個(gè)單獨(dú)的寄存器存放指向所有這些參數(shù)在用戶空間地址的指針。 給用戶空間的返回值也通過(guò)寄存器傳遞源譬。在x86系統(tǒng)上集惋,它存放在eax寄存器中。接下來(lái)許多關(guān)于系統(tǒng)調(diào)用處理程序的描述都是針對(duì)x86版本的踩娘。但不用擔(dān)心刮刑,所有體系結(jié)構(gòu)的實(shí)現(xiàn)都很類似。最終依據(jù)具體調(diào)用號(hào)調(diào)用對(duì)應(yīng)的系統(tǒng)調(diào)用處理過(guò)程并使用傳遞的參數(shù).
總結(jié)
系統(tǒng)調(diào)用在用戶空間進(jìn)程和硬件設(shè)備之間的接口养渴,它和普通庫(kù)函數(shù)調(diào)用非常相似雷绢,只是系統(tǒng)調(diào)用由操作系統(tǒng)核心提供,運(yùn)行于核心態(tài)理卑,而普通的函數(shù)調(diào)用由函數(shù)庫(kù)或用戶自己提供翘紊,運(yùn)行于用戶態(tài)。主要有三個(gè)作用:
它為用戶空間提供了一種統(tǒng)一的硬件的抽象接口藐唠。比如當(dāng)需要讀些文件的時(shí)候帆疟,應(yīng)用程序就可以不去管磁盤類型和介質(zhì),甚至不用去管文件所在的文件系統(tǒng)到底是哪種類型宇立。
系統(tǒng)調(diào)用保證了系統(tǒng)的穩(wěn)定和安全踪宠。作為硬件設(shè)備和應(yīng)用程序之間的中間人,內(nèi)核可以基于權(quán)限和其他一些規(guī)則對(duì)需要進(jìn)行的訪問(wèn)進(jìn)行裁決妈嘹。舉例來(lái)說(shuō)柳琢,這樣可以避免應(yīng)用程序不正確地使用硬件設(shè)備,竊取其他進(jìn)程的資源蟋滴,或做出其他什么危害系統(tǒng)的事情染厅。
每個(gè)進(jìn)程都運(yùn)行在虛擬系統(tǒng)中痘绎,而在用戶空間和系統(tǒng)的其余部分提供這樣一層公共接口津函,也是出于這種考慮。如果應(yīng)用程序可以隨意訪問(wèn)硬件而內(nèi)核又對(duì)此一無(wú)所知的話孤页,幾乎就沒(méi)法實(shí)現(xiàn)多任務(wù)和虛擬內(nèi)存尔苦,當(dāng)然也不可能實(shí)現(xiàn)良好的穩(wěn)定性和安全性。在Linux中,系統(tǒng)調(diào)用是用戶空間訪問(wèn)內(nèi)核的惟一手段允坚;除異常和中斷外魂那,它們是內(nèi)核惟一的合法入口。
API與系統(tǒng)調(diào)用并不存在一一對(duì)應(yīng)的關(guān)系稠项,只是為用戶提供的標(biāo)準(zhǔn)接口涯雅,提高了程序移植性。用戶在請(qǐng)求系統(tǒng)調(diào)用的時(shí)候展运,一般只與API打交道活逆。而內(nèi)核只與系統(tǒng)調(diào)用打交道,至于API是怎樣申請(qǐng)系統(tǒng)調(diào)用的拗胜,是由Glibc等標(biāo)準(zhǔn)制定者負(fù)責(zé)的蔗候。UNIX尊奉的一句話是:Provide mechanism, not policy,即提供機(jī)制而不是策略埂软。這里的機(jī)制就是:
用戶空間的程序無(wú)法直接執(zhí)行內(nèi)核代碼锈遥。它們不能直接調(diào)用內(nèi)核空間中的函數(shù),因?yàn)閮?nèi)核駐留在受保護(hù)的地址空間上勘畔。如果進(jìn)程可以直接在內(nèi)核的地址空間上讀寫的話所灸,系統(tǒng)安全就會(huì)失去控制。所以炫七,應(yīng)用程序應(yīng)該以某種方式通知系統(tǒng)庆寺,告訴內(nèi)核自己需要執(zhí)行一個(gè)系統(tǒng)調(diào)用,希望系統(tǒng)切換到內(nèi)核態(tài)诉字,這樣內(nèi)核就可以代表應(yīng)用程序來(lái)執(zhí)行該系統(tǒng)調(diào)用了懦尝。
通知內(nèi)核的機(jī)制是靠軟件中斷實(shí)現(xiàn)的。首先壤圃,用戶程序?yàn)橄到y(tǒng)調(diào)用設(shè)置參數(shù)陵霉。其中一個(gè)參數(shù)是系統(tǒng)調(diào)用編號(hào)。參數(shù)設(shè)置完成后伍绳,程序執(zhí)行“系統(tǒng)調(diào)用”指令踊挠。x86系統(tǒng)上的軟中斷由int產(chǎn)生。這個(gè)指令會(huì)導(dǎo)致一個(gè)異常:產(chǎn)生一個(gè)事件冲杀,這個(gè)事件會(huì)致使處理器切換到內(nèi)核態(tài)并跳轉(zhuǎn)到一個(gè)新的地址效床,并開(kāi)始執(zhí)行那里的異常處理程序。此時(shí)的異常處理程序?qū)嶋H上就是系統(tǒng)調(diào)用處理程序权谁。它與硬件體系結(jié)構(gòu)緊密相關(guān)剩檀。
新地址的指令會(huì)保存程序的狀態(tài),計(jì)算出應(yīng)該調(diào)用哪個(gè)系統(tǒng)調(diào)用旺芽,調(diào)用內(nèi)核中實(shí)現(xiàn)那個(gè)系統(tǒng)調(diào)用的函數(shù)沪猴,恢復(fù)用戶程序狀態(tài)辐啄,然后將控制權(quán)返還給用戶程序。系統(tǒng)調(diào)用是設(shè)備驅(qū)動(dòng)程序中定義的函數(shù)最終被調(diào)用的一種方式运嗜。