那么在今天的文章中我們從理論來(lái)到現(xiàn)實(shí),看看Linux中的系統(tǒng)調(diào)用是怎樣實(shí)現(xiàn)的。
首先我們先來(lái)簡(jiǎn)單復(fù)習(xí)下之前講解過(guò)的知識(shí)。
系統(tǒng)調(diào)用和普通的函數(shù)調(diào)用沒(méi)有本質(zhì)區(qū)別,普通的函數(shù)調(diào)用一般調(diào)用的是我們自己編寫(xiě)的函數(shù)或者其它庫(kù)函數(shù),而系統(tǒng)調(diào)用調(diào)用的則是內(nèi)核中的函數(shù),更學(xué)術(shù)一點(diǎn)的說(shuō)法是這樣的,所謂系統(tǒng)調(diào)用是指用戶(hù)態(tài)程序請(qǐng)求操作系統(tǒng)提供的服務(wù)。
一提到服務(wù),大家最先想到的一定是服務(wù)器,假設(shè)客戶(hù)端是瀏覽器,瀏覽器發(fā)送http請(qǐng)求,服務(wù)器接收到請(qǐng)求后進(jìn)行解析然后調(diào)用相應(yīng)的hander, 從本質(zhì)上講就是客戶(hù)端觸發(fā)了服務(wù)器端的某個(gè)函數(shù)的運(yùn)行 ,這時(shí)我們說(shuō)客戶(hù)端請(qǐng)求了服務(wù)器端上的服務(wù)。
而系統(tǒng)調(diào)用與此類(lèi)似,只不過(guò)用戶(hù)態(tài)程序并不是通過(guò)http觸發(fā)了操作系統(tǒng)中某個(gè)函數(shù)的運(yùn)行,而是通過(guò)機(jī)器指令來(lái)觸發(fā)的,因?yàn)橛脩?hù)態(tài)的App和操作系統(tǒng)運(yùn)行在同一臺(tái)計(jì)算機(jī)系統(tǒng)上,而客戶(hù)端和服務(wù)器端運(yùn)行在不同的計(jì)算機(jī)系統(tǒng)中(絕大部分情況下),因此客戶(hù)端只能通過(guò)網(wǎng)絡(luò)協(xié)議http來(lái)與服務(wù)器進(jìn)行通信。
更通俗的說(shuō)法就是所謂系統(tǒng)調(diào)用是指用戶(hù)態(tài)的某個(gè)函數(shù)調(diào)用內(nèi)核中的某個(gè)函數(shù)。
接下來(lái)我們用一段簡(jiǎn)單的hello world程序看下系統(tǒng)調(diào)用,這段程序需要運(yùn)行在x86_64下:
.datamsg: .ascii "Hello, world!\\n" len = . - msg.text .global _start_start: movq $1, %rax movq $1, %rdi movq $msg, %rsi movq $len, %rdxsyscall movq $60, %rax xorq %rdi, %rdisyscall
使用以下命令編譯:
$ gcc -c test.S
$ ld -o test test.o
然后執(zhí)行:
./test
Hello, world!
這段匯編代碼成功的打印出了hello world,這段代碼是什么意思呢?
注意看.data這一段,這里說(shuō)的是程序定義了哪些數(shù)據(jù),.text段是說(shuō)程序中包含了哪些執(zhí)行,我們之前提到進(jìn)程的內(nèi)存布局時(shí)總是說(shuō)數(shù)據(jù)段以及代碼段,這里的數(shù)據(jù)段指的就是匯編中的.data段、代碼段指的就是匯編中的.text段,現(xiàn)在你應(yīng)該明白了吧。
在.text段我們看到了一條略顯奇怪的指令,syscall,這條指令是什么意思呢?
我們來(lái)翻看一下intel的開(kāi)發(fā)手冊(cè):
SYSCALL invokes an OS system-call handler at privilege level 0. It does so by loading RIP from the IA32_LSTAR MSR (after saving the address of the instruction following SYSCALL into RCX). (The WRMSR instruction ensures that the IA32_LSTAR MSR always contain a canonical address.)
這段話(huà)告訴我們intel處理器在執(zhí)行syscall指令時(shí)會(huì)在內(nèi)核態(tài)調(diào)用操作系統(tǒng)的某個(gè)函數(shù),即syscall-call handler,這個(gè)過(guò)程就是所謂的系統(tǒng)調(diào)用,我們知道CPU執(zhí)行某個(gè)函數(shù)時(shí)必須知道某個(gè)函數(shù)在內(nèi)存中的地址,那么CPU是怎么知道某個(gè)syscall-call handler的內(nèi)存地址呢?
原來(lái)syscall-call handler所在的內(nèi)存地址存儲(chǔ)在寄存器MSR中,那么又是誰(shuí)將這個(gè)地址存儲(chǔ)在了寄存器MSR中呢?很顯然是操作系統(tǒng),接下來(lái)以L(fǎng)inux為例來(lái)講解。
Linux內(nèi)核初始化時(shí)將syscall-call handler也就是Linux內(nèi)核中entry_SYSCALL_64函數(shù)的地址寫(xiě)入寄存器MSR中:
wrmsrl(MSR_LSTAR, entry_SYSCALL_64);
其中syscall-call handler也就是entry_SYSCALL_64定義在了Linux源碼中的arch/x86/entry/entry_64.S,上述初始化寄存器MSR的代碼定義在了arch/x86/kernel/cpu/common.c。
現(xiàn)在我們知道了,當(dāng)CPU執(zhí)行syscall時(shí)會(huì)無(wú)腦跳轉(zhuǎn)到寄存器MSR中保存的函數(shù)地址,也就是entry_SYSCALL_64函數(shù),那么很顯然的,所有系統(tǒng)調(diào)用的入口都是entry_SYSCALL_64函數(shù),那么操作系統(tǒng)該怎么區(qū)分到底是調(diào)用的read系統(tǒng)調(diào)用還是write等系統(tǒng)調(diào)用?
原來(lái),操作系統(tǒng)中給每種系統(tǒng)調(diào)用分配了一個(gè)序號(hào),就像Linux中這樣:
0 common read sys_read
1 common write sys_write
2 common open sys_open
3 common close sys_close
4 common stat sys_newstat
5 common fstat sys_newfstat
6 common lstat sys_newlstat
7 common poll sys_poll
8 common lseek sys_lseek
9 common mmap sys_mmap
...
可以看到,0號(hào)系統(tǒng)調(diào)用表示的是內(nèi)核中的read函數(shù),1號(hào)系統(tǒng)調(diào)用表示的內(nèi)核中的write函數(shù),在進(jìn)行系統(tǒng)調(diào)用時(shí)會(huì)將表示系統(tǒng)調(diào)用類(lèi)別的序號(hào)寫(xiě)入通用寄存器中。
從上面這個(gè)表格中可以看到write系統(tǒng)調(diào)用的序號(hào)是1,因此在hello world程序中我們將1寫(xiě)入寄存器rax中:
movq $1, %rax
這條指令就表示我們將要調(diào)用第1號(hào)系統(tǒng)調(diào)用,也就是sys_write,hello world程序中后續(xù)三條機(jī)器指令的函數(shù)是:
# 寫(xiě)入文件描述符1
movq $1, %rdi
# 保存指向字符串的指針
movq $msg, %rsi
# 寫(xiě)入數(shù)據(jù)的大小
movq $len, %rdx
實(shí)際上這四條機(jī)器指令都是為執(zhí)行syscall進(jìn)行的鋪墊,也就是執(zhí)行syscall所需要的參數(shù),可以看到我們進(jìn)行系統(tǒng)調(diào)用傳遞參數(shù)時(shí)都是通過(guò)寄存器來(lái)完成的。
這樣當(dāng)CPU執(zhí)行syscall執(zhí)行時(shí)就會(huì)跳轉(zhuǎn)到Linux內(nèi)核中的write函數(shù),同時(shí)在執(zhí)行該函數(shù)時(shí)也能知道write函數(shù)所需要的參數(shù)是什么。
好啦,這篇就到這里,最后,我準(zhǔn)備開(kāi)通知識(shí)星球啦,我會(huì)把所有文章中留下的問(wèn)題總結(jié)在這里,同時(shí)也鼓勵(lì)大家在這里輸出自己的深度、系統(tǒng)性的思考,沉淀出屬于自己的知識(shí)。
-
Linux
+關(guān)注
關(guān)注
87文章
11207瀏覽量
208717 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4277瀏覽量
62323 -
系統(tǒng)調(diào)用
+關(guān)注
關(guān)注
0文章
28瀏覽量
8317
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論