SwiftCoreにおけるユーザープロセス起動時の引数(argc, argv)および環境変数(envp)の受け渡し仕様を定義する。
本仕様は System V ABI (x86-64) および Linux のプロセス起動処理に準拠する。
カーネルはユーザーモードへ移行する直前に、ユーザースタックを以下のように構築する。 スタックは高位アドレスから低位アドレスに向かって伸長するため、図の上方が高位アドレスとなる。
|-------------------| <--- ユーザースタック領域の最大アドレス (Stack Top)
| 文字列データ領域 | 引数の文字列本体 ("arg0\0", "arg1\0"...)
| | 環境変数の文字列本体 ("KEY=VAL\0"...)
|-------------------|
| パディング | 16バイト境界整列用 (必要に応じて)
|-------------------|
| 補助ベクトル | (将来的な拡張用、終端は {0, 0})
| (Auxv) |
|-------------------|
| NULL (8 bytes) | envp 配列の終端
| envp[m] | 環境変数ポインタ (8bytes)
| ... |
| envp[0] | 環境変数ポインタ配列の先頭
|-------------------|
| NULL (8 bytes) | argv 配列の終端
| argv[n-1] | 引数ポインタ (8bytes)
| ... |
| argv[0] | 引数ポインタ配列の先頭 (通常はプログラム名)
|-------------------|
| argc (8 bytes) | 引数の数 (符号なし整数)
|-------------------| <--- 初期 RSP (エントリポイント実行開始時)
ユーザーモードの実行開始時点(_start 呼び出し時)でのレジスタの状態は以下の通りとする。
- RSP: 上記スタックレイアウトの
argcの位置を指していること。 - RIP: アプリケーションのエントリポイント(ELFヘッダで指定されたアドレス)。
- RFLAGS: 割り込み許可 (IF=1) などの適切な初期値。
- その他の汎用レジスタ(RDI, RSI, RDX, RCX, R8, R9 等)は未定義(または 0 クリア)。
exec システムコール等のプロセス生成処理において、以下の手順でスタックを構築する。
- スタック領域のマップ: ユーザースタック用のメモリページを確保・マップする。
- 文字列のコピー: 引数および環境変数の文字列データをスタックの高位アドレス側にコピーする。
- ポインタ配列の作成: コピーした文字列アドレスを指すポインタ配列 (
argv,envp) をスタックにプッシュする。 - argc のプッシュ: 引数の数をスタックにプッシュする。
- RSP の決定: 最終的なスタックポインタの値を計算し、スレッドコンテキストの
rspに設定する。
アプリケーションのスタートアップコード(Rust の場合は crt.rs や _start)は、スタック上のデータを引数として取得し、main 関数へ渡す。
fn main(argc: i32, argv: *const *const u8) -> i32- argc の取得: スタックトップ (
[rsp]) から値を取り出し、第1引数レジスタrdiに格納する。pop rdi
- argv の取得:
argcをポップした直後のスタックポインタ (rsp) がargv[0]を指しているため、そのアドレスを第2引数レジスタrsiに格納する。mov rsi, rsp
- スタックアライメント: 必要に応じてスタックポインタを 16 バイト境界に整列させる(SSE 命令等を使用する場合)。
and rsp, -16
- main 呼び出し:
call main
- 終了処理:
mainの戻り値 (rax) を引数としてexitシステムコールを呼び出す。