張建幫 原創作品轉載請註明出處 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000
關於linux的系統調用,以下這張圖片可以解釋得比較清楚:
這幅圖片以fork()函數爲例,詳細闡述了系統調用的具體的步驟與流程:
- 在源文件中使用的
fork()
函數會調用函數庫中的fork()
函數- 函數庫中的
fork()
會將sys_fork
的系統調用號2
保存在eax
寄存器中,然後調用int $0x80
指令自陷,進入內核態- 系統根據立即數
$0x80
,到IDT(Interrupt Descriptor Table,中斷描述符表)中找到對應的中斷處理程序的入口地址- 開始執行中斷處理程序
- 中斷處理程序根據
eax
寄存器中存儲的系統調用號,到SCT
(Systerm call table,系統調用表)中找到sys_fork()
的入口地址- 執行
sys_fork
系統調用明白了整個系統調用的流程後,我們就可以通過嵌入式彙編直接調用想調用的系統調用了,具體流程如下:
- 查詢相應的系統調用號
- 將系統調用號保存到
eax
寄存器中- 通過
int $0x80
指令自陷- 函數調用完成,自動將結果(返回值)保存在
eax
寄存器中- 將
eax
寄存器的內容進行輸出
整體的流程相當於把函數庫中的工作實現了一遍。
現在以 getpid
爲例,分別用C函數庫和嵌入式彙編(查看嵌入式彙編相關知識)實現其系統調用:
(getpid的系統調用號是 20
,點這裏查看完整的系統調用列表)
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("pid is %d\n",getpid());
int pidAsm = 0;
asm volatile(
"mov $0, %%ebx\n\t" //系統調用第一個參數,清零,不清零好像也沒影響
"mov $20, %%eax\n\t" //保存系統調用號
"int $0x80\n\t" //自陷
"mov %%eax, %0\n\t" //將結果保存到變量 pidAsm中
: "=m"(pidAsm)
);
printf("using asm,pid is %d\n", pidAsm);
}
運行結果如下:
可以看到,兩種方式得到的結果是一樣的,這也印證了我們的猜想。