システムコール - kentakozuka/yetos GitHub Wiki

低い権限で動くプログラムから、高い権限でしか動作できないプログラムを呼び出す仕組み

実現方法

  • syscall命令
  • 割り込みを使用した方法
  • io_uring
  • OSの関数を直接呼び出す

syscall命令

  • AMDのx86系プロセッサーでシステムコール用に用意された命令

簡単なsyscall命令の例 EAXレジスタに固定値を設定し、RCXをR10にコピーしたあと、syscallを実行する。

bits 64
section .text

global SyscallLogString
SyscallLogString:
  mov eax, 0x800000000
  mov r10, rcx
  syscall
  ret

呼び出し規約

  • 呼び出し規約(calling conventions)とは、何か処理(手続きや関数)を呼び出すときに、引数と戻り値をどうやってやりとりするかを定めるもの
  • 呼ぶ側(caller)と呼ばれる側(callee)それぞれが、CPUのレジスタやスタックをどのように利用するかを規定する
  • 基本的にはCPUとOSの組み合わせで定義されるが、言語やコンパイラでも異なることがある

AMD64/x86-64の呼び出し規約

System V AMD64 ABI

  • Windows以外の多くのOS(Linux、BSD系、macOS)の呼び出し規約はこれ
  • 最初の6つの整数またはポインタの引数は汎用レジスタ(RDI, RSI, RDX, RCX, R8, R9)で渡される
  • 最初の8つの浮動小数点数はベクタレジスタ(XMM0~XMM7)で渡される
  • 汎用レジスタとベクタレジスタは独立して使われるので、下記の関数fではaがRDI、bがXMM0で渡される
int f(int a, double b);

レジスタに収まらなかった引数はスタックで渡される。 スタックには引数の後ろの方から積んでいく。 スタックに積むとメモリアドレスは小さくなっていくので、メモリレイアウトとしては、引数の順番に並ぶことになる。 可変長引数の場合は少し特殊で、ベクタレジスタを使用した個数がALレジスタに渡される。 可変長引数のcalleeの例として、va_argを使った関数のアセンブリ出力を見てみたところ、まずALレジスタの個数だけベクタレジスタをスタックの専用領域に保存し、va_argで浮動小数点数を取り出す時にそこから取得する、ということをしていた。

va_argで取り出す型によって取り出す場所が違うということは、入れ替えできるのだろうか? ということでやってみると、

printf("%d %d %.2f %.2f\n", 1, 2, 3.0, 4.0);
printf("%d %d %.2f %.2f\n", 3.0, 4.0, 1, 2);

以下のように同じ結果になった。 ※ ただし後者はコンパイラには順番が違うと怒られる。

1 2 3.00 4.00
1 2 3.00 4.00

なお、プロトタイプ宣言していない関数を呼び出す場合、その関数が可変長引数を取る関数かどうかは不明なので、ALレジスタがセットされる。 すなわち、きちんとプロトタイプ宣言しないと無駄が生じる可能性がある。

LINUXシステムコール

syscalls - Linux のシステムコール

YetOSでのシステムコール呼び出し

mermaid-diagram-2022-07-27-080316

mermaid
sequenceDiagram
    participant app as App
    participant newlib as App(Newlib)
    participant cpu as CPU
    participant os as OS
    os->>cpu: Register entry point
    app->>newlib: Call wrapper function
    newlib->>app: Call custom function
    app->>cpu: Call syscall instruction<br/>- syscall number
    cpu->>os: Execute entry point
    Note over os: Execute function!

Loading

システムコール一覧

プロセス関連のシステムコール

fork

  • プロセスを作る (コピーする)

execve

  • 現プロセスで指定のプログラムを実行する
  • 変種: exec{v,l}p?e? (引数の渡し方, 微妙な意味の 違い)
  • 以下, 総称して exec と呼ぶ (実際には exec という名前 の関数はない)

exit

  • 現プロセスを終了する
  • exit

waitpid

  • 子プロセスの終了待ち + 処理
  • 変種: wait, wait3, wait4

参考

⚠️ **GitHub.com Fallback** ⚠️