ここでは、Windows、Linux、OSXで実行可能ファイルを実行するとどうなるかをまとめたいと思います。特に、操作の順序を正確に理解したいと思います。実行可能ファイル形式(PE、ELF、またはMach-O)はカーネルによってロードされると思います(ただし、 のさまざまなセクションは無視します) [〜#〜] elf [〜#〜] (Executable and Linkable Format)とその意味)、そして参照を解決するダイナミックリンカーがあり、次に__init
実行可能ファイルの一部が実行され、次にメイン、次に__fini
、そしてプログラムは完了しますが、それは非常にラフで、おそらく間違っていると確信しています。
編集:質問はCWになりました。私はLinuxをいっぱいにしています。 WinとOSXで同じことをしたい人がいたら、それは素晴らしいことです。
もちろん、これは非常に高く抽象的なレベルです。
Executable - No Shared Libary:
Client request to run application
->Shell informs kernel to run binary
->Kernel allocates memory from the pool to fit the binary image into
->Kernel loads binary into memory
->Kernel jumps to specific memory address
->Kernel starts processing the machine code located at this location
->If machine code has stop
->Kernel releases memory back to pool
Executable - Shared Library
Client request to run application
->Shell informs kernel to run binary
->Kernel allocates memory from the pool to fit the binary image into
->Kernel loads binary into memory
->Kernel jumps to specific memory address
->Kernel starts processing the machine code located at this location
->Kernel pushes current location into an execution stack
->Kernel jumps out of current memory to a shared memory location
->Kernel executes code from this shared memory location
->Kernel pops back the last memory location and jumps to that address
->If machine code has stop
->Kernel releases memory back to pool
JavaScript/.NET/Perl/Python/PHP/Ruby (Interpretted Languages)
Client request to run application
->Shell informs kernel to run binary
->Kernel has a hook that recognises binary images needs a JIT
->Kernel calls JIT
->JIT loads the code and jumps to a specific address
->JIT reads the code and compiles the instruction into the
machine code that the interpretter is running on
->Interpretture passes machine code to the kernel
->kernel executes the required instruction
->JIT then increments the program counter
->If code has a stop
->Jit releases application from its memory pool
RouteNpingmeが言うように、レジスタはCPU内に設定され、魔法が起こります!
更新:ええ、今日はきちんと話すことができません!
わかりました、私自身の質問に答えます。これは段階的に行われ、Linux(およびおそらくMach-O)に対してのみ行われます。個人的な回答に自由に追加して、賛成を得られるようにしてください(そして、現在はCWになっているので、バッジを取得できます)。
途中から始めて、残りを見つけたら構築します。このドキュメントは、x86_64、gcc(GCC)4.1.2で作成されています。
このセクションでは、カーネルの観点から、プログラムが呼び出されたときに、プログラムを実行する準備ができるまでに何が起こるかについて説明します。
_startは(PLTを介して)glibcで__libc_start_mainを呼び出し、次の情報を渡します。
_initが呼び出されます
Windowsでは、最初に画像がメモリにロードされます。カーネルは、必要になるライブラリ(「DLL」を読み取る)を分析し、それらもロードします。
次に、プログラムイメージを編集して、必要な各ライブラリ関数のメモリアドレスを挿入します。これらのアドレスは、.EXEバイナリにすでにスペースがありますが、ゼロで埋められているだけです。
次に、各DLLのDllMain()プロシージャが、依存関係の順序に従うように、最も必要なDLL)から最後まで1つずつ実行されます。
すべてのライブラリがロードされて準備が整うと、最終的にイメージが開始されます。現在何が起こるかは、使用される言語、使用されるコンパイラ、およびプログラムルーチン自体によって異なります。
画像がメモリに読み込まれるとすぐに、魔法が引き継ぎます。
正確な定義によっては、.NetやJavaなどの言語のJITコンパイラを考慮する必要があります。技術的に「実行可能」ではない.Net「exe」を実行すると、JITコンパイラがステップインしてコンパイルします。