在这个简单的(反汇编的)C程序中,堆栈指针是怎么回事?
为了进一步了解汇编语言/计算机体系结构,我编写了以下C代码:在这个简单的(反汇编的)C程序中,堆栈指针是怎么回事?,c,assembly,x86,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 dwo
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
;为什么不只是0x24的一个子节点添加esp,字节0x10
有什么意义?leave
指令将使用隐式mov-esp,ebp
取消此操作谢谢。您告诉编译器您希望它能够快速编译,而不是生成好的代码,并且生成易于像
gdb
这样的调试器交互的代码。在-O0
模式下,gcc不会在同一函数的不同部分之间进行太多优化,因此在调用后添加esp,0x10
以弹出堆栈,然后单独离开
-O0
非常嘈杂(满是存储/重新加载),所以作为一个人阅读很糟糕
如果您看到的函数需要几个int
参数并返回一个int
,那么您的运气会更好。您可以在函数上使用\uuuu属性(noinline))
来阻止它们内联
例如,请查看上的一个简单函数。另请参见标记wiki。您忘记启用优化。编译器生成良好的代码,但不一定是最好的代码,无论是否进行优化。例如,可能会生成两个连续的子esp
指令,因为它们是出于两个不同的原因生成的。您看到的代码是管理“堆栈框架”以及参数和局部变量。“每种语言都是不同的”关于它是如何做到这一点的。这就是为什么在单个项目中调用库或混合语言会很棘手的原因之一。这取决于编译器(及其版本)和初学者的命令行选项。例如,如果使用gcc,那么在查看代码时,它可能非常有意义。在一个地方可能有一个调整,因为一件事,另一个原因,而那些地方是窥视孔优化器无法到达的。或者你没有使用任何优化的编译器,甚至连窥视孔都没有……没有理由假设编译器每次都能生成完美的代码。它们在大型项目上的效率远远高于人工,但人工几乎总能在某个地方修复/调整编译器遗漏的东西。