【问题标题】:Why does gcc place a “halt” instruction in programs after the call to “main”?为什么 gcc 在调用“main”之后会在程序中放置“halt”指令?
【发布时间】:2011-07-09 23:11:24
【问题描述】:

在 Linux/i386 系统上查看 gcc 生成的 elf 可执行文件时,它似乎总是在调用“main”之后和“nop”填充之前放置一个停止指令(0xf4),例如:

│ ....... ! entrypoint:
│ ....... !   xor         ebp, ebp
│ 80482e2 !   pop         esi
│ 80482e3 !   mov         ecx, esp*emphasized text*
│ 80482e5 !   and         esp, 0fffffff0h
│ 80482e8 !   push        eax
│ 80482e9 !   push        esp
│ 80482ea !   push        edx
│ 80482eb !   push        __libc_csu_fini
│ 80482f0 !   push        __libc_csu_init
│ 80482f5 !   push        ecx
│ 80482f6 !   push        esi
│ 80482f7 !   push        main
│ 80482fc !   call        wrapper_804a004_80482c4
│ 8048301 !   hlt                                      <--- halt instruction
│ 8048302 !   nop
│ 8048303 !   nop
│ 8048304 !   nop
               ⋮

这样做的目的是什么? 永远不应达到此代码。这是某种保护措施吗?

【问题讨论】:

  • 你确定这是由 gcc 生成的,而不是从运行时库链接的函数的一部分吗?
  • @Ben:这很好。不,它很可能由运行时库完成。但为什么? :-)

标签: linux gcc assembly glibc


【解决方案1】:

main 返回后,exit 将被调用。如果系统的 exit 版本没有立即停止进程的执行,则 hlt 存在。在用户模式下,它会导致一个保护错误,这将杀死该进程。如果进程由于某种原因在环 0 中运行,它将停止处理器直到下一次中断,这将有望触发操作系统删除进程。在设计为在环 0 中运行的进程中,通常在 hlt 之后有一条 jmp 指令,这将导致 hlt 一遍又一遍地执行,直到进程终止。

【讨论】:

  • 谢谢!这确实是有道理的。我找到了代码,评论证实了意图:goo.gl/gsE6Q
【解决方案2】:

您是对的 - 永远不应访问此代码,并且可能在开发时将其留在那里作为保护措施。有堆栈操作来防止调用返回。

更多:http://www.win.tue.nl/~aeb/linux/hh/stack-layout.html

【讨论】:

    【解决方案3】:

    我认为这是一种保护措施,但实际上可能不起作用。一方面,hlt 是一条特权指令,这意味着它将在环 3(大多数应用程序运行的地方)中执行时抛出异常。充其量,它可能对内核代码有用,但如果启用了中断,那么 hlt 只会持续到处理器收到中断,然后处理器将继续执行 nop 填充。

    【讨论】:

    • 对。这是一个特权指令。执行它的用户空间程序将出现段错误——我猜这可能是意图——但我仍然不知道为什么人们会想要这样。 :-)
    • 特别是因为只有在 exit() 失败后才能到达。
    猜你喜欢
    • 2020-01-01
    • 2017-05-14
    • 1970-01-01
    • 2011-09-04
    • 2020-03-26
    • 1970-01-01
    • 2022-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多