为什么gcc在调用“main”后会在程序中放置“暂停”指令?

时间:2011-03-06 21:17:35

标签: linux gcc assembly glibc

在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
               ⋮

这是为了什么目的? 永远不应该达到此代码。这是某种保障吗?

3 个答案:

答案 0 :(得分:11)

主要返回后,将调用exit。如果系统的exit版本没有立即停止执行进程,那么hlt就在那里。在用户模式下,它将导致保护错误,这将导致进程终止。如果进程由于某种原因在环0中运行,它将停止处理器直到下一个中​​断,这将有希望触发操作系统删除进程。在设计为在环0中运行的进程中,在hlt之后通常会有一条jmp指令,这将导致hlt反复执行,直到进程终止。

答案 1 :(得分:3)

我认为它是一种保护措施,可能实际上并不起作用。例如,hlt是一个priveldged指令,这意味着它将在环3(大多数应用程序运行)中执行时抛出异常。最好的情况是,它可能对内核代码很有用,但如果启用了中断,那么hlt将只持续到处理器获得中断,然后处理器将继续执行nop填充。

答案 2 :(得分:0)

你是对的 - 永远不应该达到这个代码,并且可能在开发时作为保护措施。有堆栈操作来防止回叫。

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