ie传递给系统调用的数据区域太小_【Linux系列】系统调用
在現(xiàn)代OS中,內(nèi)核提供了用戶進(jìn)程與內(nèi)核進(jìn)行交互的一組接口。這些接口讓應(yīng)用程序受限地訪問硬件設(shè)備,提供了創(chuàng)建新進(jìn)程并與已有進(jìn)程進(jìn)行通信的機(jī)制,也提供了申請OS其他資源的能力。
系統(tǒng)調(diào)用在用戶空間進(jìn)程和硬件設(shè)備之間添加了一個(gè)中間層。該層主要作用有三個(gè):
為用戶空間提供了一種硬件的抽象接口
保證了系統(tǒng)的穩(wěn)定和安全
每個(gè)進(jìn)程都運(yùn)行在虛擬系統(tǒng)中,而在用戶空間和系統(tǒng)的其余部分提供這樣一層公共接
??Linux—OS的系統(tǒng)調(diào)用是用戶空間訪問內(nèi)核的唯一手段;除異常和陷入外,是內(nèi)核唯一的合法入口。實(shí)際上其他的像設(shè)備文件和/proc之類的方式,最終還是通過系統(tǒng)調(diào)用進(jìn)行訪問的。
1.API: 一般情況下,應(yīng)用程序通過在用戶空間實(shí)現(xiàn)的應(yīng)用編程接口API而不是直接通過系統(tǒng)調(diào)用來編程。因?yàn)閍pplication使用的API實(shí)際上并不需要和內(nèi)核提供的系統(tǒng)調(diào)用對應(yīng)。一個(gè)API定義了一組應(yīng)用程序使用的編程接口。 ??在Unix中最流行的應(yīng)用編程接口是基于POSIX標(biāo)準(zhǔn)的。 ???POSIX是由IEEE的一組標(biāo)準(zhǔn)組成,其目標(biāo)是提供一套大體上基于Unix的可移植OS標(biāo)準(zhǔn)。在大多數(shù)Unix系統(tǒng)上,根據(jù)POSIX定義的API函數(shù)和系統(tǒng)調(diào)用之間有著直接關(guān)系;非Unix系統(tǒng)如Windows也提供了與POSIX兼容的庫。 Linux的系統(tǒng)調(diào)用作為C庫的一部分提供。C庫實(shí)現(xiàn)了Unix系統(tǒng)的主要API,同時(shí)提供了POSIX的絕大部分API。Unix的系統(tǒng)調(diào)用抽象出了用于完成某種確定的目的函數(shù),不需要內(nèi)核關(guān)心函數(shù)的使用。 |
系統(tǒng)調(diào)用syscall通過C庫中定義的函數(shù)調(diào)用來進(jìn)行,會通過一個(gè)long類型的返回值來表示成功or錯(cuò)誤。在出現(xiàn)錯(cuò)誤時(shí)C庫會把錯(cuò)誤碼寫入errno全局變量。通過調(diào)用perror()庫函數(shù)可以把該變量翻譯成用戶可以理解的錯(cuò)誤字符串。
~如何定義系統(tǒng)調(diào)用?
1.注意函數(shù)聲明中的asmlinkage限定詞,這是一個(gè)編譯指令,通知編譯器僅從棧中提取該函數(shù)的參數(shù)。所有的syscall都需要這個(gè)asmlinkage限定詞。
2.函數(shù)返回long類型。為了保證32 bit和64 bit系統(tǒng)兼容,syscall在用戶空間(返回int)和內(nèi)核空間(返回long)由不同的返回值類型。
3.注意系統(tǒng)調(diào)用get_pid()在內(nèi)核中被定義成sys_getpid()——命名規(guī)則
【系統(tǒng)調(diào)用號】
在Linux中,每個(gè)系統(tǒng)調(diào)用syscall被賦予一個(gè)唯一系統(tǒng)調(diào)用號。
當(dāng)用戶空間的進(jìn)程執(zhí)行一個(gè)系統(tǒng)調(diào)用時(shí),這個(gè)系統(tǒng)調(diào)用號就用來指明到底是要執(zhí)行哪個(gè)系統(tǒng)調(diào)用;進(jìn)程不會提及系統(tǒng)調(diào)用的名稱。
???Linux有一個(gè)“未實(shí)現(xiàn)”系統(tǒng)調(diào)用sys_ni_syscall(),只返回?zé)o效的系統(tǒng)調(diào)用錯(cuò)誤號-ENOSYS。
??內(nèi)核sys_call_table記錄了系統(tǒng)調(diào)用表中的所有已注冊過的syscall列表,該表為每一個(gè)有效的系統(tǒng)調(diào)用指定了唯一的系統(tǒng)調(diào)用號。
【syscall性能】
Linux系統(tǒng)調(diào)用比其他許多OS執(zhí)行都要快。
很短的上下文切換時(shí)間
系統(tǒng)調(diào)用處理程序和每個(gè)系統(tǒng)調(diào)用本身都很簡潔
【系統(tǒng)調(diào)用處理程序】
用戶空間的程序無法直接執(zhí)行內(nèi)核代碼,因?yàn)閮?nèi)核駐留在受保護(hù)的地址空間上。那么需要通知內(nèi)核要執(zhí)行一個(gè)系統(tǒng)調(diào)用,其機(jī)制是靠軟中斷實(shí)現(xiàn)的。
軟中斷~通過引發(fā)一個(gè)異常來促使系統(tǒng)切換到內(nèi)核態(tài)去執(zhí)行異常處理程序,此時(shí)的異常處理程序即為系統(tǒng)調(diào)用處理程序。 ??X86系統(tǒng)上預(yù)定義的軟中斷是128,通過int$0x80指令觸發(fā)該中斷。這條指令會觸發(fā)一個(gè)異常導(dǎo)致系統(tǒng)切換到內(nèi)核態(tài)并執(zhí)行第128號異常處理程序/系統(tǒng)調(diào)用處理程序system_call()。 ??X86增加了sysenter指令提供了更快、更專業(yè)的陷入內(nèi)核執(zhí)行系統(tǒng)調(diào)用的方式。 |
A.指定恰當(dāng)?shù)膕yscall
因所有的系統(tǒng)調(diào)用陷入內(nèi)核方式一樣,必須把系統(tǒng)調(diào)用號一并傳給內(nèi)核。在X86上,系統(tǒng)調(diào)用號是通過eax寄存器傳遞給內(nèi)核的。
system_call()函數(shù)通過將給定的系統(tǒng)調(diào)用號與NR_syscalls做比較來檢查其有效性。若 >= NR_syscalls,該函數(shù)就返回-ENOSYS。否則就執(zhí)行相應(yīng)的syscall:
call *sys_call_table(, %rax, 8)
B.參數(shù)傳遞
除了系統(tǒng)調(diào)用號以外,大部分系統(tǒng)調(diào)用都還需要一些外部的參數(shù)輸入。可以像傳遞系統(tǒng)調(diào)用號把這些參數(shù)從用戶空間傳給內(nèi)核。
在X86-32系統(tǒng)上,ebx、ecx、edx、esi和edi按照順序存放前5個(gè)參數(shù)。
【系統(tǒng)調(diào)用實(shí)現(xiàn)】
1.系統(tǒng)調(diào)用實(shí)現(xiàn)
每個(gè)系統(tǒng)調(diào)用都應(yīng)該有一個(gè)明確的用途。在Linux中不提倡采用多用途的syscall(一個(gè)系統(tǒng)調(diào)用通過傳遞不同的參數(shù)值來選擇完成不同的工作)。Unix主張?zhí)峁C(jī)制而不是策略。
系統(tǒng)調(diào)用的接口應(yīng)該力求簡潔,參數(shù)盡可能少。
系統(tǒng)調(diào)用的語義和行為非常關(guān)鍵,因?yàn)閼?yīng)用程序依賴于它們。
盡量為將來多考慮,考慮其擴(kuò)展性。
2.參數(shù)驗(yàn)證
系統(tǒng)調(diào)用必須仔細(xì)檢查它們所有的參數(shù)是否合法有效。syscall在內(nèi)核空間執(zhí)行,如果任由用戶將不合法的輸入傳遞給內(nèi)核,那么系統(tǒng)的安全和穩(wěn)定將受到影響。
??最重要的一種檢查就是檢查用戶提供的指針是否有效。在接收一個(gè)用戶空間的指針之前,內(nèi)核必須保證:
指針指向的內(nèi)存區(qū)域?qū)儆谟脩艨臻g。~進(jìn)程絕不能欺騙內(nèi)核去讀內(nèi)核空間的data
指針指向的內(nèi)存區(qū)域在進(jìn)程的地址空間里。~進(jìn)程絕不能欺騙內(nèi)核去讀其他進(jìn)程的data
如果是讀,該內(nèi)存應(yīng)被標(biāo)記為可讀;
如果是寫,該內(nèi)存應(yīng)被標(biāo)記為可寫;
如果是可行,該內(nèi)存應(yīng)被標(biāo)記為可執(zhí)行
~進(jìn)程絕不能繞過內(nèi)存訪問限制~
內(nèi)核提供了2個(gè)方法來完成必須的檢查和內(nèi)核空間<=>用戶空間之間data的來回拷貝。
??內(nèi)核無論何時(shí)都不能輕率地接受來自用戶空間的指針!??
1.copy_to_user():向用戶空間寫入data 該函數(shù)有3個(gè)參數(shù),分別為進(jìn)程空間中的目的內(nèi)存地址、內(nèi)核空間內(nèi)的源地址、需要拷貝的data長度。 2.copy_from_user():從用戶空間讀取data 該函數(shù)有3個(gè)參數(shù)與1相似,把第二個(gè)參數(shù)指定位置上的data拷貝到第一個(gè)參數(shù)指定的位置上,拷貝的數(shù)據(jù)長度由第三個(gè)參數(shù)決定。 【返回值】 若失敗,返回的是沒能完成拷貝的數(shù)據(jù)字節(jié)數(shù);若成功則為0。 |
新版本的Linux允許檢查針對特定資源的特殊權(quán)限。調(diào)用者可以使用capable()函數(shù)來檢查是否有權(quán)對指定的資源進(jìn)程操作(0無非0有)。默認(rèn)情況下,屬于超級用戶的進(jìn)程擁有所有權(quán)利而非超級用戶沒有任何權(quán)利。Linux/capability.h包含一份所有這些權(quán)能和其對應(yīng)的權(quán)限列表。
【系統(tǒng)調(diào)用上下文】
內(nèi)核在執(zhí)行syscall時(shí)處于進(jìn)程上下文。在進(jìn)程上下文中,內(nèi)核可以休眠(如在系統(tǒng)哦給你調(diào)用阻塞or顯式調(diào)用schedule()時(shí))并且可以被搶占。
休眠表明系統(tǒng)調(diào)用可以使用內(nèi)核提供的絕大部分功能。
可搶占表明當(dāng)前的進(jìn)程可被其他進(jìn)程搶占。
??????因?yàn)樾碌倪M(jìn)程可能使用相同的系統(tǒng)調(diào)用,所以必須保證系統(tǒng)調(diào)用是可重入的。
當(dāng)系統(tǒng)調(diào)用返回時(shí),控制權(quán)仍然在system_call()中,它最終負(fù)責(zé)切換到用戶空間并讓用戶進(jìn)程繼續(xù)執(zhí)行下去。
1.綁定一個(gè)系統(tǒng)調(diào)用的最后步驟
當(dāng)編寫完一個(gè)系統(tǒng)調(diào)用后,要把它注冊成一個(gè)正式的系統(tǒng)調(diào)用。如下步驟:
在系統(tǒng)調(diào)用表的最后加入一個(gè)表項(xiàng)。??index從0開始
對于所支持的各種體系結(jié)構(gòu),系統(tǒng)調(diào)用號都必須定于中
系統(tǒng)調(diào)用必須被編譯進(jìn)內(nèi)核映像(而不能編譯成模塊)。需要把它放入kernel/下的一個(gè)相關(guān)文件即可。
2.從用戶空間訪問系統(tǒng)調(diào)用
通常系統(tǒng)調(diào)用靠C庫支持。用戶程序通過包含標(biāo)準(zhǔn)文件并和C庫鏈接,就可使用syscall。
??Linux本身提供了一組宏,用于直接對系統(tǒng)調(diào)用進(jìn)行訪問。它會設(shè)置好寄存器并調(diào)用陷入指令。這些宏是_syscalln(),其中n的范圍[0, 6],代表需要傳遞給系統(tǒng)調(diào)用的參數(shù)個(gè)數(shù)。對于每個(gè)宏,都有2 + 2*n個(gè)參數(shù)。
~例如:
open()系統(tǒng)調(diào)用定義如下:
long open(const char *filename,int flags, int mode)而不靠庫支持,直接調(diào)用此系統(tǒng)調(diào)用的宏的形式如下:
#define NR_open 5_syscall3(long,??open,?const?char?*filename,int?flags,?int?mode)其中l(wèi)ong為返回值類型,open為系統(tǒng)調(diào)用名稱,后面為參數(shù)信息。
該宏會被擴(kuò)展成為內(nèi)嵌匯編的C函數(shù);由匯編語言執(zhí)行。將系統(tǒng)調(diào)用號和參數(shù)壓入寄存器并觸發(fā)軟中斷來陷入內(nèi)核。
3.why不通過系統(tǒng)調(diào)用的方式實(shí)現(xiàn)???
~建立一個(gè)new系統(tǒng)調(diào)用的好處:
系統(tǒng)調(diào)用創(chuàng)建容易且使用方便
Linux系統(tǒng)調(diào)用的高性能顯而易見
引發(fā)的問題:
需要一個(gè)內(nèi)核在處于開發(fā)版本時(shí)由官方分配的系統(tǒng)調(diào)用號
系統(tǒng)調(diào)用被加入穩(wěn)定內(nèi)核后就被固化了,為了避免應(yīng)用程序崩潰,它的接口不允許改動
需要將系統(tǒng)調(diào)用分別注冊到每個(gè)需要支持的體系結(jié)構(gòu)中去
在腳本中不容易調(diào)用系統(tǒng)調(diào)用,也不能從文件系統(tǒng)直接訪問系用調(diào)用
由于需要系統(tǒng)調(diào)用號,因此在住內(nèi)核樹外是很難維護(hù)和使用系統(tǒng)調(diào)用的
如果僅僅進(jìn)行簡單的信息狡猾,系統(tǒng)調(diào)用就大材小用了
??不要以為你以為的就是你以為的~這很哲學(xué)??
~替代方法:
實(shí)現(xiàn)一個(gè)設(shè)備節(jié)點(diǎn),并對此實(shí)現(xiàn)read()和write()。使用ioctl()對特定的設(shè)置進(jìn)行操作or對特定的信息進(jìn)行檢索。
像信號量接口,可以用文件描述符來表示。因此也就可以按上述方式對其操作
把增加的信息作為一個(gè)文件放在sysfs的合適位置
Linux系統(tǒng)盡量避免每出現(xiàn)一種新抽象就簡單的加入一個(gè)new系統(tǒng)調(diào)用。新系統(tǒng)調(diào)用增添頻率很低也反映出了Linux是一個(gè)相對穩(wěn)定且功能較為完善的OS。
總結(jié)
以上是生活随笔為你收集整理的ie传递给系统调用的数据区域太小_【Linux系列】系统调用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python对象列表转换为字典_pyth
- 下一篇: linux安装python3.6_Lin