c - 这个简单(反汇编)C 程序中的堆栈指针发生了什么?

标签 c assembly x86

通过更多地了解汇编语言/计算机体系结构,我编写了以下 C 代码:

int my_caller() {
    int a = my_callee(0xbaba);
    return a;
}

int my_callee(int a) {
    return a;
}

这会反汇编(在我的机器上;带有一些添加的注释)如下:

; my_caller function
push ebp
mov ebp,esp
sub esp,byte +0x18
sub esp,byte +0xc
push dword 0xbaba
call dword 0x1e
add esp,byte +0x10
mov [ebp-0xc],eax
mov eax,[ebp-0xc]
leave
ret

; my_callee function
push ebp
mov ebp,esp
mov eax,[ebp+0x8]
pop ebp
ret

关于my_calleresp的处理:

  1. 为什么我们将 esp 子化为 0x18,然后是 0xc;为什么不只是 0x24 的单个子?
  2. my_callee返回后,add esp,byte 0x10有什么意义?无论如何,leave 指令将通过隐式 mov esp,ebp 取消此操作。

谢谢。

最佳答案

你告诉编译器你希望它能够快速编译,而不是生成好的代码,并且生成对于调试器来说很容易的代码,例如 gdb与之互动。在 -O0模式下,gcc 不会在同一函数的不同部分之间进行太多优化,因此 add esp, 0x10调用后弹出堆栈,然后 leave分别。

-O0非常嘈杂(充满了存储/重新加载),因此作为人类阅读很糟糕。

你会更幸运地看到需要几个 int 的函数args 并返回 int 。您可以使用__attribute__((noinline))在函数上阻止它们内联。

看一下 Godbolt compiler explorer 上的一个简单函数, 例如。另请参阅标签维基。

关于c - 这个简单(反汇编)C 程序中的堆栈指针发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38039526/

相关文章:

linux - 对 X86_64 linux : Why should we write mov [digit], al 的程序集中标签的使用感到困惑,但不是 mov digit, al?

c - 为什么指针内存能够成功地从无效内存分配中保存和检索数据

c - 将 execvp 与 dup2 一起使用会引发 EFAULT 错误

assembly - x86-64 规范地址?

java - 使用编译器从 Java 到机器代码

c++ - 计算 trampoline hook 的 JMP 指令地址

c - 为什么这个矩阵乘法算法比另一个更快?

c - 有哪些实现尾调用消除的好方法?

optimization - 为什么 GCC 需要出于神秘原因清除 edx?

linux - 内存分段边界检查是如何完成的?