我最近利用了一个危险程序,并发现了 x86-64 架构上的 gcc
版本之间的一些有趣的差异。
注意:
错误使用
gets
不是这里的问题。如果我们将
gets
替换为任何其他函数,问题不会改变。
这是我使用的源代码:
#include <stdio.h>
int main()
{
char buf[16];
gets(buf);
return 0;
}
我使用gcc.godbolt.org使用标志 -m32 -fno-stack-protector -z execstack -g
反汇编程序。
在反汇编代码中,当 gcc
版本 >= 4.9.0 时:
lea ecx, [esp+4] # begin of main
and esp, -16
push DWORD PTR [ecx-4] # push esp
push ebp
mov ebp, esp
/* between these comment is not related to the question
push ecx
sub esp, 20
sub esp, 12
lea eax, [ebp-24]
push eax
call gets
add esp, 16
mov eax, 0
*/
mov ebp, esp
mov ecx, DWORD PTR [ebp-4] # ecx = saved esp
leave
lea esp, [ecx-4]
ret # end of main
但是版本<4.9.0的gcc只是:
push ebp # begin of main
mov ebp, esp
/* between these comment is not related to the question
and esp, -16
sub esp, 32
lea eax, [esp+16]
mov DWORD PTR [esp], eax
call gets
mov eax, 0
*/
leave
ret # end of main
我的问题是:反汇编代码出现这种差异的原因及其好处是什么?这种技术有名字吗?
最佳答案
如果没有实际值,我无法确定:
and esp, 0xXX # XX is a number
但这看起来很像额外的代码,用于将堆栈对齐到比 ABI 要求的更大的值。
编辑:该值为 -16,即 32 位 0xFFFFFFF0
或 64 位 0xFFFFFFFFFFFFFFF0
所以这确实是堆栈对齐到 16 字节,可能是为了使用上交所指令。正如评论中提到的,>= 4.9.0 版本中有更多代码,因为它还对齐帧指针而不仅仅是堆栈指针。
关于gcc 版本 >= 4.9.0 与 gcc 版本 < 4.9 上的这种改进的原因和好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41302625/