`execve()`は特別な起動ルーチンとmain()関数をどのように呼び出すのですか?

`execve()`は特別な起動ルーチンとmain()関数をどのように呼び出すのですか?

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()crt0main()

ありがとうございます。

答え1

execveどのカーネルコードもこの関数_start(呼称に関係なく実行可能ファイルのエントリポイント)を呼び出しません。

別の場所で走っているからです。コンテキスト;まるで別のコンピュータで動作しているようです。

カーネルはexecveユーザーモードに戻るときにシステムコールをスケジュールしIP(コマンドポインタ)、レジスタを関数の先頭を指すように設定し、_startSPスタックポインタ)レジスタを関数の先頭を指すように設定します。 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

関連情報