C/C++ プログラムでは、システム (Windows、Linux、Mac OS X) はどのようにして main() 関数を呼び出しますか?

StackOverflow https://stackoverflow.com/questions/12332

  •  08-06-2019
  •  | 
  •  

質問

OSが関数を呼び出すよりも技術的な説明を探しています。誰か私を助けてくれたり、ウェブサイトや本を教えてくれたりしませんか?

役に立ちましたか?

解決

.exe ファイル (または他のプラットフォームの同等ファイル) には、「エントリ ポイント」アドレスが含まれています。最初の近似では、OS は .EXE ファイルの関連セクションを RAM にロードし、エントリ ポイントにジャンプします。

他の人が言ったように、このエントリポイントは「メイン」ではなく、ランタイムライブラリの一部になります。静的オブジェクトの初期化、argc/argvパラメータの設定、stdin/stdout/stderrの設定などのことを行います。 、など。それがすべて完了すると、main() 関数が呼び出されます。main が終了すると、ランタイムは戻りコードを環境に戻し、静的デストラクターを呼び出し、_atexit ルーチンを呼び出すなど、同様のプロセスを実行します。

MS ツール (おそらく無料のツールではない) を持っている場合は、すべてのランタイム ソースが手に入ります。それを確認する簡単な方法は、main() メソッドの右中括弧にブレークポイントを置き、シングル ステップでバックアップすることです。ランタイムに移行します。

他のヒント

main() これは C ライブラリの一部であり、システム関数ではありません。OS X や Linux の場合はわかりませんが、Windows は通常、次のコマンドでプログラムを開始します。 WinMainCRTStartup(). 。このシンボルはプロセスを初期化し、コマンド ライン引数と環境を抽出します (argc, argv, end)そして電話します main(). 。また、その後に実行するコードを呼び出す役割もあります。 main(), 、 のように atexit().

Visual Studio ファイルを調べると、デフォルトの実装を見つけることができるはずです。 WinMainCRTStartup それが何をするのかを見るために。

起動時に呼び出す独自の関数を定義することもできます。これは、リンカ オプションの「エントリ ポイント」を変更することによって行われます。これは多くの場合、引数をとらず、void を返す関数です。

Windows に関する限り、エントリ ポイント関数は次のとおりです。

  • コンソール: void __cdecl mainCRTStartup( void ) {}
  • GUI: void __stdcall WinMainCRTStartup( void ) {}
  • DLL: BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL,DWORD fdwReason,void* lpReserved) {}

通常の main/WinMain/DllMain ではなくこれらを使用する唯一の理由は、独自のランタイム ライブラリを使用したい場合 (ファイル サイズを小さくしたい場合やカスタム機能が必要な場合) です。

カスタム ランタイムの実装と、より小さい PE ファイルを取得するためのその他のテクニックについては、以下を参照してください。

エキスパート C++/CLI (279 ページあたりを確認してください) には、ネイティブ、混合、および純粋な CLR アセンブリのさまざまなブートストラップ シナリオの非常に具体的な詳細が記載されています。

OSに依存します。OS X では、Mach ヘッダーに EIP (命令ポインター) レジスタの開始アドレスを含むフレームがあります。

バイナリがロードされると、OS は次のアドレスから実行を開始します。

cristi:test diciu$ otool -l ./a.out | grep -A 10 LC_UNIXTHREAD
        cmd LC_UNIXTHREAD
    cmdsize 80
     flavor i386_THREAD_STATE
      count i386_THREAD_STATE_COUNT
[..]
        ss  0x00000000 eflags 0x00000000 eip 0x00001f8c cs  0x00000000
[..]

アドレスは、バイナリの「start」関数のアドレスです。

cristi:test diciu$ nm ./a.out
0000200c D _NXArgc
00002008 D _NXArgv
00002000 D ___progname
00001fe0 t __dyld_func_lookup
00001000 A __mh_execute_header
[..]
00001f8c T start

Mac OS X では、「main」関数よりも先に呼び出されるのは「start」関数です。

(gdb) b start
Breakpoint 1 at 0x1f90
(gdb) b main
Breakpoint 2 at 0x1ff4
(gdb) r
Starting program: /Users/diciu/Programming/test/a.out 
Reading symbols for shared libraries ++. done

Breakpoint 1, 0x00001f90 in start ()

Windows および Win32 API に関連する書籍に興味がある場合は、試してみてください。

「Microsoft Windows 用アプリケーションのプログラミング」Jeffrey Richter 著。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top