31

しばらくの間、おそらく最初のバグのない C プログラムを作成したことを非常に誇りに思いました。ソースコード全体は次のとおりです。

int main;

がなくても問題なくコンパイルできますintが、(なくても) 警告が出て-Wall、バグのないプログラムを目指すプログラマーとしてはエラー扱いです。

このアプリケーションを喜んでコンパイルしたので、すぐに急いで起動しました。驚いたことに、セグメンテーション違反エラーが表示されました...


今真剣に。正確に何が起こっているのですか?

私の推測は次のとおりです。それはmainの定義の欠如です。これは非常に明白ですが、コンパイラはそれを許可しています。OK、main別の単位で定義されている可能性があります。しかし、リンカーでさえそれについて何もしません。特に理由は?

4

1 に答える 1

20

この単語mainは、任意の変数の正式な名前です。典型的なユースケースは、名前の関数をmainコンパイラに提供することです。コンパイラはそれをオブジェクトファイルにコンパイルし、次にリンクされてcrt0.o、実行時の初期化(スタック割り当てなど)を提供し、ラベルにジャンプしmainます。

C オブジェクト ファイルでは、シンボルはプロトタイプに関連付けられておらず、リンカはint main;ジャンプ先のメイン プログラムとしてグローバル変数をリンクすることに成功しています。しかし、このプログラムはゴミです。ほとんどの場合、ゼロとして初期化されますが、プロセッサはすぐに、プログラムに割り当てられたデータ空間 (スタック + ヒープ) の外部のメモリにアクセスするランダムな命令に遭遇するか、命令フローが予約されたコード空間の限界に達します。

どちらもセグメンテーション違反を引き起こします。実際、システムが実行フラグのあるアーキテクチャで実行されている場合、プログラムは実行許可なしでデータセグメントまたはページにジャンプしようとする最初の試行で segfault を起こします。

コメントでの議論をサポートするためのさらなる読み物: Data Execute PreventionNX_bit

于 2013-03-11T07:36:32.750 に答える