📖 推薦閱讀:《Yocto項目實戰教程:高效定制嵌入式Linux系統》
🎥 更多學習視頻請關注 B 站:嵌入式Jerry
系統調用入口機制:多架構對比理解(以 ARM64 為主)
本篇內容聚焦于系統調用的入口實現機制,重點以 ARM64 架構為例,同時對比 x86 和 RISC-V 架構的實現方式,從多角度幫助構建系統調用的總體認知體系。
一、系統調用的核心概念
- 定義:系統調用是用戶態程序請求內核服務的一種受控方式。
- 目的:實現從用戶態到內核態的“安全切換”,如文件訪問、進程創建、內存管理等。
- 典型例子:
open()
,read()
,write()
,fork()
等。
二、系統調用的觸發方式對比
架構 | 觸發指令 | 注釋 | 觸發入口源文件位置 |
---|---|---|---|
ARM64 | svc #0 | 使用 SVC(Supervisor Call)陷入內核 | arch/arm64/kernel/entry.S |
x86 | int $0x80 / syscall | 前者為老方式,后者為現代 CPU 使用方式 | arch/x86/entry/entry_64.S |
RISC-V | ecall | 通過環境調用指令陷入內核 | arch/riscv/kernel/entry.S |
三、以 ARM64 為例的系統調用執行流程
🔹 1. 用戶態觸發
int fd = open("/etc/passwd", O_RDONLY);
- glibc 中
open()
→syscall(SYS_open, ...)
- 執行
svc #0
指令,觸發異常
🔹 2. 異常向量入口
// arch/arm64/kernel/entry.S
el0_sync:bl el0_svc
說明:el0_sync
是從 EL0(用戶態)同步異常進入 EL1(內核態)的處理入口。
🔹 3. C 語言調用鏈
el0_sync└── el0_svc (arch/arm64/kernel/entry-common.c)└── do_el0_svc() (arch/arm64/kernel/syscall.c)└── syscall_trace_enter() + invoke_syscall()
-
invoke_syscall()
中執行:- 讀取
x8
(系統調用號) - 查表:
sys_call_table[x8]
- 執行對應系統調用實現函數,如
__arm64_sys_open()
- 讀取
四、系統調用參數與返回值對比
架構 | 參數傳遞寄存器 | 系統調用號寄存器 | 返回值寄存器 |
---|---|---|---|
ARM64 | x0 ~x5 | x8 | x0 |
x86 | eax , ebx , ecx … | eax | eax |
RISC-V | a0 ~a5 | a7 | a0 |
五、系統調用表與綁定機制
系統調用表是 syscall number 與實際內核函數之間的映射橋梁,實現“按號調用”的機制。
🔹 syscall 表文件位置
架構 | 系統調用表路徑 |
---|---|
ARM64 | arch/arm64/kernel/syscall_table.S |
x86 | arch/x86/entry/syscalls/syscall_64.tbl |
RISC-V | arch/riscv/kernel/syscall_table.c |
🔹 syscall 映射機制
- 用戶態設置 syscall number(如 ARM64 用
x8
) - 內核讀取 syscall number,從 syscall 表中查找對應函數指針
- 執行綁定的系統調用函數(如
__arm64_sys_open()
)
🔸 例子(ARM64 的 syscall_table.S):
.long __arm64_sys_open // 對應 __NR_open
.long __arm64_sys_read // 對應 __NR_read
🔹 SYSCALL_DEFINE 展開示意
SYSCALL_DEFINE3(open, const char __user *filename, int flags, umode_t mode)
- 宏展開后生成
__arm64_sys_open()
- 并作為 syscall 表的一項注冊
六、完整調用路徑梳理(ARM64)
用戶態↓
svc #0 (用戶態發起陷入)↓
el0_sync (arch/arm64/kernel/entry.S)↓
el0_svc (arch/arm64/kernel/entry-common.c)↓
do_el0_svc (arch/arm64/kernel/syscall.c)↓
syscall_trace_enter → invoke_syscall()↓
sys_call_table[x8] → __arm64_sys_open()
七、調試與分析工具推薦
工具 | 用途 |
---|---|
strace | 跟蹤用戶態發起的系統調用 |
ftrace | 跟蹤內核態 syscall 調用鏈 |
gdb | 可調試匯編入口與寄存器設置 |
objdump / readelf | 查看符號表與 ELF 結構 |
八、常見問題總結
問題 | 答案 |
---|---|
系統調用是中斷嗎? | 是一種同步異常(軟中斷),可類比中斷處理但不同于 IRQ。 |
為什么每種架構入口不一樣? | 不同指令集的陷入方式、特權級切換方式、寄存器約定不一樣。 |
系統調用號在哪設置? | 通常在用戶態庫中寫入指定寄存器(如 ARM64 的 x8 )。 |
怎么找到系統調用函數? | 查 syscall 表,通過 syscall number 定位函數指針。 |
參數怎么傳? | 不同架構采用不同寄存器(x0 |
syscall 表作用是什么? | 它是內核中系統調用號和函數之間的查找映射表,按號定位函數地址執行。 |
📌 本文重點理解系統調用的“陷入路徑”,構建從用戶態到內核態的調用跳轉邏輯。后續配合“系統調用如何連接內核子系統”篇章,深入剖析 syscall 如何與 VFS、進程管理等模塊協作。