通过更多地了解汇编语言/计算机体系结构,我编写了以下 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_caller
中esp
的处理:
- 为什么我们
将 esp 子化
为 0x18,然后是 0xc;为什么不只是 0x24 的单个子? - 从
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 上的一个简单函数, 例如。另请参阅x86标签维基。
关于c - 这个简单(反汇编)C 程序中的堆栈指针发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38039526/