gcc - x86 asm - 从 esp 中减去 12 个字节。只需要8个

标签 gcc assembly x86

我已经用 gcc (gcc -ggdb -mpreferred-stack-boundary=2 -o demo demo.c) 编译了这段代码并反编译它以查看程序集(我知道它使用了不安全的函数,这是为了练习缓冲区溢出):

#include<stdio.h>

CanNeverExecute()
{
        printf("I can never execute\n");
        exit(0);
}

GetInput()
{
        char buffer[8];

        gets(buffer);
        puts(buffer);
}

main()
{
        GetInput();

        return 0;
}

这是 GetInput() 函数的程序集:

(gdb) disas GetInput
Dump of assembler code for function GetInput:
   0x08048432 <+0>: push   ebp
   0x08048433 <+1>: mov    ebp,esp
   0x08048435 <+3>: sub    esp,0xc
=> 0x08048438 <+6>: lea    eax,[ebp-0x8]
   0x0804843b <+9>: mov    DWORD PTR [esp],eax
   0x0804843e <+12>:    call   0x8048320 <gets@plt>
   0x08048443 <+17>:    lea    eax,[ebp-0x8]
   0x08048446 <+20>:    mov    DWORD PTR [esp],eax
   0x08048449 <+23>:    call   0x8048340 <puts@plt>
   0x0804844e <+28>:    leave  
   0x0804844f <+29>:    ret    
End of assembler dump.

这是 Main() 函数的程序集:

(gdb) disas main
Dump of assembler code for function main:
   0x08048450 <+0>: push   ebp
   0x08048451 <+1>: mov    ebp,esp
   0x08048453 <+3>: call   0x8048432 <GetInput>
   0x08048458 <+8>: mov    eax,0x0
   0x0804845d <+13>:    pop    ebp
   0x0804845e <+14>:    ret    
End of assembler dump.

我在第 13 行设置了一个断点 (gets(buffer))

从 Main() 中,我可以看到 ebp 值被压入堆栈。然后,当调用 GetInput() 函数时,ret 地址也被压入堆栈。一旦进入 GetInput 函数,ebp 值将再次压入堆栈。 现在这是我感到困惑的地方:

0x08048435 <+3>: sub esp,0xc

缓冲区变量只有 8 个字节,因此应从 esp 中减去 8 个字节以允许缓冲区局部变量。

堆栈:

    (gdb) x/8xw $esp
    0xbffff404: 0x08048360  0x0804847b  0x002c3ff4  0xbffff418
    0xbffff414: 0x08048458  0xbffff498  0x00147d36  0x00000001
    (gdb) x/x &buffer
    0xbffff408: 0x0804847b

0x08048458是ret地址,0xbffff418是ebp的旧值,buffer变量的4个字节在0x0804847b,所以我猜其他4个字节是0x002c3ff4。但是堆栈上似乎还有另外 4 个字节。

所以我的问题是,如果只需要 8 个字节,为什么要减去 12 个字节?额外的 4 个字节有什么用?

谢谢

最佳答案

这是因为

mov    DWORD PTR [esp],eax

显然,您的putsgets 实现需要将参数压入堆栈。

Value [ebp-0xc] 现在实际上是 [esp],这就是 dword 提前保留的原因。

为什么会这样?这样做效率更高,因为您不必 poppush,而只需将 eax 移动到 [esp ],所以你至少节省了一条指令。但是,我猜这段代码已经过一些优化,因为这段代码很聪明。

关于gcc - x86 asm - 从 esp 中减去 12 个字节。只需要8个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30723004/

相关文章:

C代码在Tiny C Compiler下编译并运行,但在GCC下无法运行

gcc - 为什么这么简单的代码会生成这么多 LDR 和 STR 指令?

performance - 紧挨着放置使用的代码和只读数据是一个好主意吗?

assembly - x86除法异常返回地址

c++ - 在指向现有内存地址的 hpp 文件中声明成员函数的最佳方法

c++ - std::unordered_map<T,std::unique_ptr<U>> 可复制?海湾合作委员会错误?

c++ - 为什么 C++ 模板实例化失败?

c++ - 无法在 Solaris 10 上使用 GCC 5.5 包含 cmath

assembly - pic汇编中如何计算超过255?

assembly - 内存屏障是CPU执行的指令,还是只是一个标记?