在这个简单的(反汇编的)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

为了进一步了解汇编语言/计算机体系结构,我编写了以下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的处理:

  • 为什么我们通过0x18然后0xc来
    子esp
    ;为什么不只是0x24的一个子节点
  • 从我的被调用方返回后,
    添加esp,字节0x10
    有什么意义?
    leave
    指令将使用隐式
    mov-esp,ebp
    取消此操作

  • 谢谢。

    您告诉编译器您希望它能够快速编译,而不是生成好的代码,并且生成易于像
    gdb
    这样的调试器交互的代码。在
    -O0
    模式下,gcc不会在同一函数的不同部分之间进行太多优化,因此
    在调用后添加esp,0x10
    以弹出堆栈,然后
    单独离开

    -O0
    非常嘈杂(满是存储/重新加载),所以作为一个人阅读很糟糕

    如果您看到的函数需要几个
    int
    参数并返回一个
    int
    ,那么您的运气会更好。您可以在函数上使用
    \uuuu属性(noinline))
    来阻止它们内联


    例如,请查看上的一个简单函数。另请参见标记wiki。

    您忘记启用优化。编译器生成良好的代码,但不一定是最好的代码,无论是否进行优化。例如,可能会生成两个连续的
    子esp
    指令,因为它们是出于两个不同的原因生成的。您看到的代码是管理“堆栈框架”以及参数和局部变量。“每种语言都是不同的”关于它是如何做到这一点的。这就是为什么在单个项目中调用库或混合语言会很棘手的原因之一。这取决于编译器(及其版本)和初学者的命令行选项。例如,如果使用gcc,那么在查看代码时,它可能非常有意义。在一个地方可能有一个调整,因为一件事,另一个原因,而那些地方是窥视孔优化器无法到达的。或者你没有使用任何优化的编译器,甚至连窥视孔都没有……没有理由假设编译器每次都能生成完美的代码。它们在大型项目上的效率远远高于人工,但人工几乎总能在某个地方修复/调整编译器遗漏的东西。