09 系統呼叫 公司成立好了就要開始接專案

2022-06-23 23:39:11 字數 2284 閱讀 8487

1、glibc 對系統呼叫的封裝

int open(const char *pathname, int flags, mode_t mode)glibc 裡面的 open 函式

make-syscall.sh  syscall-template.s

2、系統呼叫**

3、總結

- glibc 將系統呼叫封裝成更友好的介面

- 本節解析 glibc 函式如何呼叫到核心的 open

---- 使用者程序呼叫 open 函式

- glibc 的 syscal.list 列出 glibc 函式對應的系統呼叫

- glibc 的指令碼 make_syscall.sh 根據 syscal.list 生成對應的巨集定義(函式對映到系統呼叫)

- glibc 的 syscal-template.s 使用這些巨集, 定義了系統呼叫的呼叫方式(也是通過巨集)

- 其中會呼叫 do_call (也是一個巨集), 32位與 64位實現不同

---- 32位 do_call (位於 i386 目錄下 sysdep.h)

- 將呼叫引數放入暫存器中, 由系統呼叫名得到系統呼叫號, 放入 eax

- 執行 enter_kernel(一個巨集), 對應 int $0x80 觸發軟中斷, 進入核心

- 呼叫軟中斷處理函式 entry_int80_32(核心啟動時, 由 trap_init() 配置)

- entry_int80_32 將使用者態暫存器存入 pt_regs 中(儲存現場以及系統呼叫引數), 呼叫 do_syscall_32_iraq_on 

- do_syscall_32_iraq_on 從 pt_regs 中取系統呼叫號(eax), 從系統呼叫表得到對應實現函式, 取 pt_regs 中儲存的引數, 呼叫系統呼叫

- entry_int80_32 呼叫 interrupt_ruturn(一個巨集)對應 iret 指令, 系統呼叫結果存在 pt_regs 的 eax 位置, 根據 pt_regs 恢復使用者態程序

---- 64位 do_call (位於 x86_64 目錄下 sysdep.h)

- 通過系統呼叫名得到系統呼叫號, 存入 rax; 不同中斷, 執行 syscall 指令

- msr(特殊模組暫存器), 輔助完成某些功能(包括系統呼叫)

- trap_init() 會呼叫 cpu_init->syscall_init 設定該暫存器

- syscall 從 msr 暫存器中, 拿出函式地址進行呼叫, 即呼叫 entry_syscall_64

- entry_syscall_64 先儲存使用者態暫存器到 pt_regs 中

- 呼叫 entry_syscall64_slow_pat->do_syscall_64

- do_syscall_64 從 rax 取系統呼叫號, 從系統呼叫表得到對應實現函式, 取 pt_regs 中儲存的引數, 呼叫系統呼叫

- 返回執行 usergs_sysret64(一個巨集), 對應執行 swapgs 和 sysretq 指令; 系統呼叫結果存在 pt_regs 的 ax 位置, 根據 pt_regs 恢復使用者態程序

---- 系統呼叫表 sys_call_table

- 32位 定義在 arch/x86/entry/syscalls/syscall_32.tbl 

- 64位 定義在 arch/x86/entry/syscalls/syscall_64.tbl

- syscall_*.tbl 內容包括: 系統呼叫號, 系統呼叫名, 核心實現函式名(以 sys 開頭)

- 核心實現函式的宣告: include/linux/syscall.h

- 核心實現函式的實現: 某個 .c 檔案, 例如 sys_open 的實現在 fs/open.c

- .c 檔案中, 以巨集的方式替代函式名, 用多層巨集構建函式頭

- 編譯過程中, 通過 syscall_*.tbl 生成 unistd_*.h 檔案

- unistd_*.h 包含系統呼叫與實現函式的對應關係

- syscall_*.h include 了 unistd_*.h 標頭檔案, 並定義了系統呼叫表(陣列)