我写了一个简单的 c 程序,并尝试使用 GDB 来调试程序。我了解在主要功能中使用以下内容:
进入时
push %ebp
mov %esp,%ebp
退出时
leave
ret
然后我在 _start 上尝试了 gdb,我得到了以下内容
xor %ebp,%ebp
pop %esi
mov %esp,%ecx
and $0xfffffff0,%esp
push %eax
push %esp
push %edx
push $0x80484d0
push $0x8048470
push %ecx
push %esi
push $0x8048414
call 0x8048328 <__libc_start_main@plt>
hlt
nop
nop
nop
nop
我无法理解这些台词及其背后的逻辑。
有人可以提供任何指导来帮助解释 _start
的代码吗?
最佳答案
这是评论很好的 assembly source您发布的代码。
总结起来,它做了以下事情:
- 建立一个 ebp = 0 的哨兵栈帧,这样遍历栈的代码可以很容易地找到它的终点
- 将命令行参数的数量弹出到
esi
中,以便我们可以将它们传递给__libc_start_main
- 将堆栈指针对齐到 16 位的倍数以符合 ABI。在某些 Linux 版本中不能保证会出现这种情况,因此必须手动完成以防万一。
__libc_csu_fini
、__libc_csu_init
的地址、参数向量、参数个数和main
的地址作为参数推送到__libc_start_main
__libc_start_main
被调用。此函数(源代码 here)设置一些 glibc 内部变量并最终调用main
。它永远不会回来。- 如果由于任何原因
__libc_start_main
应该返回,则在之后放置一条hlt
指令。该指令在用户代码中是不允许的,应该会导致程序崩溃(希望如此)。 nop
指令的最后一系列是由汇编程序插入的填充,因此下一个函数从 16 字节的倍数开始以获得更好的性能。它在正常执行中永远不会达到。
关于linux - 了解 C 程序中的汇编语言 _start 标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35519417/