通过学习汇编语言/计算机体系结构的更多信息,我编写了以下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
关于esp
中my_caller
的处理:
sub esp
乘以0x18然后是0xc;为什么不只是0x24的一个子?my_callee
返回后,add esp,byte 0x10
有什么意义?无论如何,leave
指令将使用隐式mov esp,ebp
。感谢。
答案 0 :(得分:2)
您告诉编译器您希望快速编译,而不是编写好的代码,并使代码很容易与gdb
之类的调试器进行交互。在-O0
模式下,gcc在同一函数的不同部分之间没有太多优化,因此add esp, 0x10
在调用后弹出堆栈,然后单独leave
。
-O0
非常嘈杂(充满了商店/重新加载),所以读作人类很糟糕。
您可以更好地查看带有几个int
args并返回int
的函数。您可以在函数上使用__attribute__((noinline))
来阻止它们进行内联。
例如,查看Godbolt compiler explorer上的简单函数。另请参阅x86标记wiki。