Cプログラムがカーネルによって実行されるときexecve()
、
という基本関数を呼び出す前に呼び出される特別な起動ルーチンはどこにありますか
execve()
?crt0
execve()
main関数はどこで呼び出されますか?
見つかりません。https://elixir.bootlin.com/linux/latest/source/fs/exec.c。
Linuxカーネルを理解することから始めて、execve()
内部的に実行可能ファイルをロードできるオブジェクトを見つけ、linux_binfmt
そのメソッドを呼び出してロードします。また、実行可能ファイルで使用される共有ライブラリをロードしてリンクするために、動的リンカーをロードします。ただし、この本ではプログラムの起動ルーチンを呼び出し、実行可能ファイルから呼び出す方法については説明しません。load_binary()
load_binary()
execve()
crt0
main()
ありがとうございます。
答え1
execve
どのカーネルコードもこの関数_start
(呼称に関係なく実行可能ファイルのエントリポイント)を呼び出しません。
別の場所で走っているからです。コンテキスト;まるで別のコンピュータで動作しているようです。
カーネルはexecve
ユーザーモードに戻るときにシステムコールをスケジュールしIP
(コマンドポインタ)、レジスタを関数の先頭を指すように設定し、_start
(SP
スタックポインタ)レジスタを関数の先頭を指すように設定します。 argv+env 文字列のリストなので、ユーザーモードの観点からは次のようになります。誰この関数を_start
次のように呼び出します。
_start(argc, argv0, argv1, ... , NULL, env0, env1, ... NULL)
すべての引数がスタックに渡される呼び出し規則から。
もちろん、これが起こる前に、カーネルはすでにこれらのargv + envを正しい場所にコピーし、関数を含む_start
セグメントをマッピングするなどの作業を担当しています。
argv + env文字列はすべて1つのブロックに含まれています。
"prog\0arg1\0arg2\0VAR1=foo\0VAR2=bar\0"
このブロックが開始および終了する仮想アドレスは、/proc/PID/stat
マニュアルprocfs(5)
ページを引用してアクセスできます。
(48) arg_start %lu (since Linux 3.5) [PT] Address above which program command-line arguments (argv) are placed. (49) arg_end %lu (since Linux 3.5) [PT] Address below program command-line arguments (argv) are placed.
ps
このアドレスに書き込むと、出力に表示されるすべての内容が変更されます。
$ sleep 3600 3600 3600 3600 3600 3600 3600 &
[2] 4927
$ awk '{print $48,$49,$49-$48-1}' /proc/4927/stat
140735402952841 140735402952882 40
$ printf 'Somebody set up us the bomb Main screen turn on\0' | dd bs=1 count=40 of
=/proc/4927/mem seek=140735402952841 conv=notrunc
40+0 records in
40+0 records out
40 bytes copied, 0.000229779 s, 174 kB/s
$ ps 4927
PID TTY STAT TIME COMMAND
4927 pts/4 S 0:00 Somebody set up us the bomb Main screen