Linuxカーネルを理解すると、順番にexecve()
呼び出されるdo_execve( )
ものが何であるかがわかります。
ファイルパス名、コマンドライン引数、および環境文字列を、新しく割り当てられた1つ以上のページフレームにコピーします。(最終的にはユーザーモードのアドレス空間に割り当てられます。)
execve()
正常終了後にプロセスが呼び出す_start
ルーチンは正しいですかrt0.o
?
APUEによると:
カーネルが(exec関数の1つを介して)Cプログラムを実行すると、メイン関数が呼び出される前に特別な起動ルーチンが呼び出されます。実行可能プログラム・ファイルは、このルーチンをプログラムの開始アドレスとして指定します。これは、リンクエディタを呼び出すときにCコンパイラによって設定されます。この起動ルーチンは、カーネルから値(コマンドライン引数と環境)を取得して設定します。その後、前に示したようにメイン関数が呼び出されます。
ルーチン__start
はこのコマンドライン引数と環境もコピーしますか?
do_execve()
コピー_start
コマンドライン引数と環境の違いは何ですか?二度コピーするのは無駄じゃないの?
ありがとうございます。
答え1
execve()が正常に終了した後、プロセスがcrt0.oの_startルーチンを呼び出すのは正しいですか?
不要。execve
システムコールが返されると、バイナリエントリポイント(ELFではe_entry
ヘッダーのフィールド)が何であれ、テキスト/コードアドレスでプロセスの実行が続行されます。例:
echo 'void run(void){ printf("in run\n"); exit(0); }' |
gcc -Wl,-e,run -nostartfiles -include stdio.h -include stdlib.h -Wall -x c - -o /tmp/run
/tmp/run
in run
_start
多くの(ほとんど?)Unixシステムのエントリポイントルーチンの一般的な名前。
ルーチン
_start
はこのコマンドライン引数と環境もコピーしますか?
これは可能ですが、通常はそのようなことはしません。やるべきことは、C関数に渡すことができるように並べ替えることですmain
。
問題は、単にエントリポイントをC関数として宣言できないことです。
_start(argc, ...)
そしてgetパラメータを使用してくださいva_args
。 onでは、x86_64
C呼び出し規則は(最初の数個)引数がレジスタに渡されると予想します。いいえどのように配達されますか_start
?
_start
通常、呼び出す前に実行する必要がある他の作業がありますmain
。非常に重要なのは、静的コンストラクタを実行することです。これはC++
静的コンストラクタを使用できます(使用すると、gcc
関数を定義してプログラムで実行できます)。C
そして__attribute__((constructor))
)。
libc.so
glibcベースのシステムの標準起動コードは、定義された関数(動的リンク)も渡します。__libc_start_main()
これは、事前にロードされた動的ライブラリでコードをオーバーライドし、バイナリ文書を変更することなく独自の初期化エントリを追加できるためです。バラよりここ例えば。