【问题标题】:What is the behavior of these linkers?这些链接器的行为是什么?
【发布时间】:2012-10-11 15:33:48
【问题描述】:

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

main;

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

int main = 0;

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

【问题讨论】:

    标签: c linker segmentation-fault


    【解决方案1】:

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

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

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

    【讨论】:

    • 那么,我可以用char main 代替int main 并期待同样的结果吗?
    • @noMAD: 是的,如果您将main 定义为任何全局对象,则会发生相同的结果,除非您碰巧正在运行具有可执行数据段的操作系统(不太可能)并且您将其初始化为在您的 CPU 上成为有效可执行代码的数据(例如,char main = 0xC3 用于 x86 上的单个 RET 指令)。
    • @noMAD 我得到了同样的结果。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 那么,我可以使用 char main 代替 int main 并期待相同的结果吗?
      • 大致而言,无论变量mainchar, double, struct { a char[300]; }, ...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      相关资源
      最近更新 更多