gcc 版本 >= 4.9.0 与 gcc 版本 < 4.9 上的这种改进的原因和好处?

标签 c gcc disassembly

我最近利用了一个危险程序,并发现了 x86-64 架构上的 gcc 版本之间的一些有趣的差异。

注意:

  1. 错误使用gets不是这里的问题。

  2. 如果我们将 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/

相关文章:

dos - x86分割、DOS、MZ文件格式、反汇编

c# - 在 .Net 中恢复本地名称

c - linux的文件锁

python - C、Perl 和 Python 相似的循环不同的结果

c - 未能释放字符指针内存 c

c - 使用 -pg 编译的 gcc 不会生成 gprof 所需的二进制文件

c - 错误与 strlen?

c - 如何将 1D char 转换为 2D int 数组并将其传递给 int C?

c - 什么是 *ABS* 部分以及何时使用?

来自 Ocaml 的汇编代码