【问题标题】:Prematurely resetting the stack pointer? Confusing assembly code过早重置堆栈指针?令人困惑的汇编代码
【发布时间】:2021-11-08 04:53:32
【问题描述】:

我试图理解一点组装的意义。

pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%edx
movl 12(%ebp),%eax
movl %ebp,%esp
movl (%edx),%edx
addl %edx,(%eax)
movl %edx,%eax
popl %ebp
ret

为什么在函数的其余部分之前将 sp 重置为基指针?为什么 %edx 中的值被移回自身?

【问题讨论】:

    标签: assembly x86 reverse-engineering stack-frame


    【解决方案1】:

    一个更短的版本是:

    mov 4(%esp), %eax
    mov 8(%esp), %edx
    mov (%edx), %edx
    add  %edx, (%eax)
    ret
    

    或者,一个粗略的 C 等价物:

    void add(int *from, int *to) {
      *to += *from;
    }
    

    编译器可能会使用 %ebp go 确保可调试的堆栈帧;并且从 %ebp 恢复 %esp 什么都不做——它们是相同的值。

    【讨论】:

    • 感谢您的快速回复,是的,预期的功能应该是基本的。我还是不太明白这是在做什么:movl (%edx), %edx
    • %edx 包含一个指针 (from),以便取消引用指针以获取其位置的值。使用 -S 编译“C”版本以查看编译器生成的内容;然后使用 -O4 之类的选项,看看它可以减少到什么。
    【解决方案2】:

    为什么在函数的其余部分之前将 sp 重置为基指针?

    在 GNU 汇编器语法中,movl %esp,%ebp 表示将 esp 移动到 ebp。 (GNU asm 语法与 Intel asm 语法的两个或多个 args 的顺序总是相反)。

    这会创建堆栈帧:局部变量和参数可以相对于%ebp 引用,如movl 8(%ebp),%edx

    popl %ebp恢复原来的%ebp,由pushl %ebp保存。


    为什么 %edx 中的值被移回自身?

    在 GNU 汇编器语法中,(%edx)%edx 中指针的间接寻址;请注意,它又是源操作数。

    【讨论】:

    • VLA 是 C99 中的新功能。当然,C11 仍然有它们,但我们通常说 C99 VLA。
    • @PeterCordes,实际上删除了该部分。这个函数中的%esp完全没有变化。
    • 对,当然不是通过 push/pop,所以 movl %ebp,%esp 只是一个错过的优化(因为可能没有启用优化),-fno-omit-frame-pointer 没有必要。
    猜你喜欢
    • 1970-01-01
    • 2014-10-17
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    相关资源
    最近更新 更多