c-这些链接者的行为是什么



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

main;

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

int main = 0;

那么链接器在这里的行为是什么呢?

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

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

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

在我的系统(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) 

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

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

当您调用未定义的行为时,任何事情都可能发生。在这里撞车是很明智的。

相关内容

  • 没有找到相关文章

最新更新