# 系統程式設計 - System Call [TOC] ## 課程影片 按:原來的課程裡面沒有專門介紹 system call,只是在介紹 buffered I/O 時簡單提到。 ### 系統程式設計 2018 W4 - 2 (00:00 ~ 32:20) {%youtube JKZKPndOIRM %} ## 文件 [`man 2 syscall`](https://man7.org/linux/man-pages/man2/syscall.2.html) 與 [`man 2 syscalls`](https://man7.org/linux/man-pages/man2/syscalls.2.html)。 ## 冷知識 ### `SYSCALL_DEFINEn` 在 Linux 核心中,系統呼叫是使用 `SYSCALL_DEFNIEn` 巨集定義的,其中 `n` 是一個非負整數。舉例來說 `fs/open.c` 中定義的 [`open`](https://elixir.bootlin.com/linux/latest/source/fs/open.c#L1224)。同樣一個檔案中也可以看到前面介紹的各種檔案操作相關系統呼叫的定義。雖說如此,但大多數系統呼叫會先進入 `glibc` 的 `__GI___libc_<syscall>` wrapper,然後當中再使用到真正的系統呼叫。 ### 系統呼叫時會保存的暫存器 `man` 裡面有滿多好資訊的。以下舉出幾個例子 系統呼叫時需要先保存暫存器。至於是哪些?這個在 [`syscall(2)`](https://man7.org/linux/man-pages/man2/syscall.2.html) 當中的 **Architecture calling conventions** 中找到: ``` Arch/ABI arg1 arg2 arg3 arg4 arg5 arg6 arg7 Notes ────────────────────────────────────────────────────────────── alpha a0 a1 a2 a3 a4 a5 - arc r0 r1 r2 r3 r4 r5 - arm/OABI r0 r1 r2 r3 r4 r5 r6 arm/EABI r0 r1 r2 r3 r4 r5 r6 arm64 x0 x1 x2 x3 x4 x5 - blackfin R0 R1 R2 R3 R4 R5 - i386 ebx ecx edx esi edi ebp - ia64 out0 out1 out2 out3 out4 out5 - m68k d1 d2 d3 d4 d5 a0 - microblaze r5 r6 r7 r8 r9 r10 - mips/o32 a0 a1 a2 a3 - - - 1 mips/n32,64 a0 a1 a2 a3 a4 a5 - nios2 r4 r5 r6 r7 r8 r9 - parisc r26 r25 r24 r23 r22 r21 - powerpc r3 r4 r5 r6 r7 r8 r9 powerpc64 r3 r4 r5 r6 r7 r8 - riscv a0 a1 a2 a3 a4 a5 - s390 r2 r3 r4 r5 r6 r7 - s390x r2 r3 r4 r5 r6 r7 - superh r4 r5 r6 r7 r0 r1 r2 sparc/32 o0 o1 o2 o3 o4 o5 - sparc/64 o0 o1 o2 o3 o4 o5 - tile R00 R01 R02 R03 R04 R05 - x86-64 rdi rsi rdx r10 r8 r9 - x32 rdi rsi rdx r10 r8 r9 - xtensa a6 a3 a4 a5 a8 a9 - ``` ### 系統呼叫的指令 除了會保存的暫存器有哪些之外,當中也有列出不同架構中,用於系統呼叫的指令各自會長怎麼樣: ``` Arch/ABI Instruction System Ret Ret Error Notes call # val val2 ─────────────────────────────────────────────────────────────────── alpha callsys v0 v0 a4 a3 1, 6 arc trap0 r8 r0 - - arm/OABI swi NR - r0 - - 2 arm/EABI swi 0x0 r7 r0 r1 - arm64 svc #0 w8 x0 x1 - blackfin excpt 0x0 P0 R0 - - i386 int $0x80 eax eax edx - ia64 break 0x100000 r15 r8 r9 r10 1, 6 m68k trap #0 d0 d0 - - microblaze brki r14,8 r12 r3 - - mips syscall v0 v0 v1 a3 1, 6 nios2 trap r2 r2 - r7 parisc ble 0x100(%sr2, %r0) r20 r28 - - powerpc sc r0 r3 - r0 1 powerpc64 sc r0 r3 - cr0.SO 1 riscv ecall a7 a0 a1 - s390 svc 0 r1 r2 r3 - 3 s390x svc 0 r1 r2 r3 - 3 superh trapa #31 r3 r0 r1 - 4, 6 sparc/32 t 0x10 g1 o0 o1 psr/csr 1, 6 sparc/64 t 0x6d g1 o0 o1 psr/csr 1, 6 tile swint1 R10 R00 - R01 1 x86-64 syscall rax rax rdx - 5 x32 syscall rax rax rdx - 5 xtensa syscall a2 a2 - - ``` 注意這些指令中,大部分是先把系統呼叫的編號存在 `System call #` 的暫存器中,然後在使用那個指令切換模式。