0

main()は他の関数と同様の関数ですが、バイナリ内のエントリ ポイント、つまりオペレーティング システムが見つけて (方法がわからない) そこからプログラムを開始するエントリ ポイントとして「マーク」されていると彼らは言います。というわけで、この機能について詳しく調べてみました。私が何をした?このコードを内部に含む単純な .C ファイルを作成しました。

int main(int argc, char **argv) {
     return (0);
}

ファイルを保存し、GCC コンパイラ (Windows、MingW 環境) をインストールして、次のようなバッチ ファイルを作成しました。

gcc -c test.c -nostartfiles -nodefaultlibs -nostdlib -nostdinc -o test.o
gcc -o test.exe -nostartfiles -nodefaultlibs -nostdlib -nostdinc -s -O2 test.o
@%comspec%

私がこれを行ったのは、非常に単純化されたコンパイラーとリンカー、ライブラリーもヘッダーもなく、コンパイラーだけを入手するためでした。したがって、コンパイルはうまくいきますが、リンクは次のエラーで停止します。

test.c:(.text+0xa): undefined reference to '___main'
collect2.exe: error: Id returned 1 exit status

メイン関数はリンカーによってエクスポートされると思いましたが、それに関する追加情報を含むライブラリは必要ないと思いました。しかし、それはそうであるように見えます。私の場合、これは標準の GCC ライブラリーでなければならないと思ったので、そのソース コードをダウンロードして、次のファイルを開きまし 。 GCC によってリンクされています。実際、メイン関数が GCC でどのように使用されているかわかりません。リンカが gcc 標準ライブラリを必要とするのはなぜですか? メインについて知るには?これにより、私の質問が非常に具体的かつ明確になったことを願っています。ありがとう!

4

2 に答える 2

5

gccがすべてのオブジェクトファイル(test.o)とライブラリをまとめてバイナリを形成する場合、gccは小さなオブジェクト(通常はcrt0.oまたはcrt1.o)も付加します。これは、の呼び出しを担当しますmain()-vコマンドラインに追加すると、gccが何をしているかを確認できます。

$ gcc -v -o test.exe test.o

crt0 / crt1はいくつかのセットアップを実行してから、mainを呼び出します。しかし、リンカは最終的にOSに従って実行可能ファイルを構築する責任があります。を使用-vすると、ターゲットシステムのオプションも表示されます。私の場合、Linux64ビット用です-m elf_x86_64。システムの場合、これはまたはのようになり-m windowsます-m mingw

于 2012-11-06T09:02:04.293 に答える
1

次の2つのオプションを使用すると、エラーが発生します。-nodefaultlibs -nostdlib

これらは、実際にを呼び出すコードを含むlibc.a/に対してコードをリンクしてはならないことをGCCに通知します。一言で言えば、すべてのOSはわずかに異なり、それらのほとんどはCとを気にしません。それぞれにプロセスを開始するための独自の特別な方法があり、それらのほとんどはCAPIと互換性がありません。c.libmain()main()

したがって、C開発者の解決策は、OSが期待するインターフェイスを含むC標準ライブラリに「グルーコード」を配置しlibc.a、標準C環境を作成することでした(メモリ割り当て構造を設定してmalloc()、OSのメモリ管理機能をマッピングします。 up stdioなど)そして最終的にはmain()

C開発者にとって、これはlibc.a、OS用に(コンパイラバイナリとともに)を取得し、セットアップがどのように機能するかを気にする必要がないことを意味します。

もう1つの混乱の原因は、参照の名前です。ほとんどのシステムでは、の記号名main()_main(つまり、1つのアンダースコア)__mainですが、はセットアップコードによって呼び出される内部関数の名前であり、最終的には実際のmain()

于 2012-11-06T09:00:35.503 に答える