Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學

Linux 內核編譯與添加系統調用完整指南

編輯:Linux 系統常見問題解答

系統調用核心原理

  • 用戶態 → 核心態:通過軟中斷 int 0x80 (x86) 或 syscall 指令 (x86_64) 觸發異常,CPU 自動切換特權級。
  • 參數傳遞:系統調用號放入 EAX/RAX,參數依次放入 EBX, ECX, EDX, ESI, EDI, EBP (x86) 或 RDI, RSI, RDX, R10, R8, R9 (x86_64)。
  • 內核入口:entry.S 中 system_call 保存現場 (SAVE_ALL),校驗調用號,查表 sys_call_table 跳轉處理函數,返回值存入 EAX,恢復現場 (RESTORE_REGS) 執行 iret 返回用戶態。

添加系統調用步驟 (以 x86_64 為例)

  1. 定義系統調用號:
    // arch/x86/entry/syscalls/syscall_64.tbl
    548  common  mycall    sys_mycall
    
  2. 聲明內核函數原型:
    // include/linux/syscalls.h
    asmlinkage long sys_mycall(int arg1, char __user *arg2);
    
  3. 實現系統調用:
    // kernel/sys_mycall.c
    #include 
    #include 
    #include 
    
    SYSCALL_DEFINE2(mycall, int, arg1, char __user *, arg2) {
        char buf[128];
        if (copy_from_user(buf, arg2, sizeof(buf)-1))
            return -EFAULT;
        buf[sizeof(buf)-1] = '\0';
        printk(KERN_INFO "mycall: arg1=%d, arg2=%s\n", arg1, buf);
        return 0;
    }
    
  4. 編譯內核:
    make menuconfig   # 確保選中 General setup -> [*] Enable system call auditing 等
    make -j$(nproc)
    make modules_install install
    
  5. 用戶空間調用:
    
    // user_test.c
    #include 
    #include 
    #include 
    #define __NR_mycall 548
    
    int main() {
        long ret = syscall(__NR_mycall, 42, "Hello Kernel");
        printf("syscall returned: %ld\n", ret);
        return 0;
    }
    

關鍵數據結構

系統調用表 (sys_call_table)


// arch/x86/kernel/sys_call_table.S (簡化)
.data
ENTRY(sys_call_table)
.long sys_restart_syscall   /* 0 */
.long sys_exit              /* 1 */
.long sys_fork              /* 2 */
.long sys_read              /* 3 */
.long sys_write             /* 4 */
.long sys_open              /* 5 */
...
.long sys_mycall            /* 548 */

現場保存/恢復宏 (entry.S)


#define SAVE_ALL \
    cld; \
    pushq %rax; pushq %rdx; pushq %rcx; pushq %rbx; \
    pushq %rsi; pushq %rdi; pushq %rbp; pushq %r8; \
    pushq %r9; pushq %r10; pushq %r11; pushq %r12; \
    pushq %r13; pushq %r14; pushq %r15; \
    movq %rsp, %rdi;          /* 將 pt_regs 指針傳給 C 處理函數 */

#define RESTORE_ALL \
    popq %r15; popq %r14; popq %r13; popq %r12; \
    popq %r11; popq %r10; popq %r9; popq %r8; \
    popq %rbp; popq %rdi; popq %rsi; popq %rdx; \
    popq %rcx; popq %rbx; popq %rax; \
    iretq

現代內核注意事項 (5.10+)

  • syscall 表分離:syscall_64.tbl 自動生成 sys_call_table 和 syscalls.h,無需手動編輯彙編文件。
  • SYSCALL_DEFINE 宏:自動處理參數拷貝、兼容層、追蹤點,推薦使用 SYSCALL_DEFINE2(name, type1, arg1, type2, arg2)。
  • 兼容性:32 位程序在 64 位內核調用需在 syscall_32.tbl 同步添加,並實現 compat_sys_xxx。
  • 安全性:嚴格使用 copy_from_user/to_user 訪問用戶指針,校驗指釖有效性 (access_ok)。

驗證與調試


# 查看系統調用是否註冊
grep mycall /proc/kallsyms
# 內核日志
dmesg | grep mycall
# 追蹤系統調用
strace -e mycall ./user_test
Copyright © Windows教程網 All Rights Reserved