4

この質問から、コンパイルして(警告はありますが)セグメンテーション違反(gcc 4.4.4; clang 2.8)を生成する面白いコードを見ました:

main;

展開すると、結果は次のようになります。

int main = 0;

では、ここでのリンカーの動作は何ですか?

4

3 に答える 3

4

mainリンカの動作は、プログラムのデータまたはBSSセグメントのいずれかで呼び出されるシンボルを定義することです。.text長さは4バイトで、0に初期化されます。通常、関数の実行可能コードを使用して、プログラムのコードセグメント(通常は)にシンボルを作成しmainます。

Cランタイムは、固定のエントリポイント(通常はと呼ばれ_startます)で起動し、一連のものを初期化し(たとえば、プログラムの引数を設定します)、main関数を呼び出します。が実行可能コードの場合main、これはすべて問題なくダンディですが、代わりに4つのゼロバイトの場合、プログラムはそれらのゼロバイトに制御を移して実行しようとします。

通常、データセグメントとBSSセグメントは実行不可としてマークされているため、そこでコードを実行しようとすると、プロセッサが例外を発生させ、OSがそれを解釈して、プログラムをシグナルで終了します。どういうわけかそれが含まれているセグメントが実行可能である場合、それはで定義されたマシン命令を実行しようとし00 00 00 00ます。x86およびx86-64では、これは不正な命令であるため、POSIXOSでもSIGILLシグナルを受け取ります。

于 2012-10-11T15:41:06.087 に答える
3

シンボルmainは、整数ではなく関数であることが期待されています。mainただし、リンカは;のタイプをあまり気にしません。シンボルが定義されています。シンボルmainが規定のシグニチャのいずれかを持つ関数でない場合は、未定義の動作を呼び出します。

次に、起動コードは「関数」を呼び出します。これは、実際にはプログラムのデータセグメント内のアドレスです。そのアドレスに格納されている「コード」が無効であるため、問題が発生します。最初の4バイトはゼロである可能性があります。後で来るのは誰かの推測です。データセグメントは実行不可とマークされている場合があります。その場合、データを実行しようとすると、そのアカウントでクラッシュが発生します。

未定義の動作を呼び出すと、何が起こる可能性があります。ここではクラッシュが非常に賢明です。

于 2012-10-11T15:39:39.353 に答える
3

私のシステム(CentOS 6.3)では、mainはBSSに配置され、すべて0が含まれているため、クラッシュします。

Program received signal SIGSEGV, Segmentation fault.
0x00000000006007f0 in main ()
(gdb) where
#0  0x00000000006007f0 in main ()
(gdb) l
"main" is not a function
(gdb) disass 0x6007f0
Dump of assembler code for function main:
=> 0x00000000006007f0 <+0>: add    %al,(%rax)
   0x00000000006007f2 <+2>: add    %al,(%rax)
End of assembler dump.
(gdb) info symbol &main
main in section .bss of /home/ajd/tmp/x
(gdb) x/16b 0x6007f0
0x6007f0 <main>:    0   0   0   0   0   0   0   0
0x6007f8:   0   0   0   0   0   0   0   0
(gdb) 
于 2012-10-11T15:40:56.737 に答える