这些连接子的行为是什么?

时间:2012-10-11 15:33:49

标签: c linker segmentation-fault

从这个question开始,我看到了一个有趣的代码编译(尽管有警告)并产生分段错误(gcc 4.4.4; clang 2.8):

main;

如果我们扩展它,结果如下:

int main = 0;

那么链接器的行为是什么?

3 个答案:

答案 0 :(得分:4)

链接器的行为是它在程序的数据或BSS段中定义了一个名为main的符号。它长4个字节并初始化为0.通常,它在程序的代码段(通常称为.text)中创建一个带有main函数可执行代码的符号。

C运行时在固定的入口点(通常称为_start)启动,初始化一堆东西(例如设置程序的参数),并调用main函数。当main是可执行代码时,这一切都很好,但是如果它是4个零字节,程序会将控制转移到那些零字节并尝试执行它们。

通常,数据和BSS段被标记为不可执行,因此当您尝试在那里执行代码时,处理器将引发异常,操作系统将解释该异常,然后使用信号终止程序。如果它所处的段是可执行的,那么它将尝试执行00 00 00 00定义的机器指令。在x86和x86-64中,这是非法指令,因此您还可以在POSIX操作系统中获得SIGILL信号。

答案 1 :(得分:3)

符号main应该是一个函数,而不是整数。但是,链接器并不太关心main的类型;符号已定义。如果符号main不是具有指定签名之一的函数,则调用未定义的行为。

启动代码然后调用'function',它实际上是程序数据段中的一个地址。它出错了,因为存储在该地址的“代码”无效 - 前4个字节可能是零;后来的是任何人的猜测。数据段可能被标记为不可执行,在这种情况下,尝试执行数据将触发该帐户崩溃。

当您调用未定义的行为时,任何事情都可能发生。崩溃是非常明智的。

答案 2 :(得分: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)