这两个函数序言指令序列有什么区别?

时间:2015-09-25 01:26:17

标签: c gcc assembly x86

测试在TypeConverter。我使用TypeConverter,优化级别32-bit x86编译了代码。我将C代码编译成二进制文件,然后使用gcc 4.2对其进行反汇编。

以下是用于函数序言的两个指令序列:

o2

请注意,在函数objdump中,寄存器0804a6f0 <quotearg_n>: 804a6f0: 8b 44 24 04 mov 0x4(%esp),%eax 804a6f4: b9 ff ff ff ff mov $0xffffffff,%ecx 804a6f9: 8b 54 24 08 mov 0x8(%esp),%edx 804a6fd: c7 44 24 04 40 e1 04 movl $0x804e140,0x4(%esp) 804a704: 08 804a705: e9 c6 fa ff ff jmp 804a1d0 <quotearg_n_options> 804a70a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi 0804a730 <quotearg>: 804a730: 83 ec 1c sub $0x1c,%esp 804a733: 8b 44 24 20 mov 0x20(%esp),%eax 804a737: c7 04 24 00 00 00 00 movl $0x0,(%esp) 804a73e: 89 44 24 04 mov %eax,0x4(%esp) 804a742: e8 a9 ff ff ff call 804a6f0 <quotearg_n> 804a747: 83 c4 1c add $0x1c,%esp 804a74a: c3 ret 804a74b: 90 nop 804a74c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi 在使用quotearg之前会被用来访问堆栈并获得一些参数。根据我的经验,我认为esp然后0x1c模式对于使用sub编译的指令非常常见。

但请注意,在函数access中,注册O2直接添加quotearg_n以访问堆栈。 (我认为地址esp的指令的意思是将呼叫站点的返回地址设置为注册0x4,我是对的......?)根据我的观察,第一个函数使用的模式很少见,0x804a6f0编译的中等大小C程序eax约为5%。

所以这是我的问题:

为什么编译器以类似gcc的方式生成函数序言指令?从地址O2开始的前三条指令的确切含义是什么?

为什么编译器总是按照quoterag_n然后0x804a6f0模式生成函数序言指令? (例如sub

我清楚了吗?非常感谢

1 个答案:

答案 0 :(得分:1)

sub %esp的那个是典型的堆叠式房间,然后将args放在那里,然后调用一个函数。您还可以这样做以保留空间,以便将寄存器中的本地变量溢出到内存中。

第一个是尾调用优化,只是在将一些值加载到寄存器后跳转到quotearg_n_options。最终调用的参数与我们输入quotearg_n时堆栈中的args相同。

它可以逃脱这个因为它不需要任何堆栈空间用于局部变量。

我不确定它对4(%esp)做了什么。我认为其中一个args存在,因为它将它设置为常数。 IIRC,(%esp)是返回地址,4(%esp)是第一个arg。它将第一个arg设置为常量,可能是缓冲区的地址。我不清楚为什么它可能会做其他一些事情,除非它跳到quotearg_n_options的中间,%edx中的值可能很重要。 (并且可以解释为什么它将堆栈中的其他args加载到callees可以破坏的寄存器中。