【发布时间】:2014-04-26 10:32:01
【问题描述】:
我不明白为什么以下行使用movl 将数据推送到堆栈指针下方是由 GCC 生成的。
movl -4(%ebp), %eax # -4(%ebp) <- local variable 1
movl 8(%ebp), %edx # 8(%ebp) <- first parameter
movl %edx, 8(%esp) # ??? WHY NOT: pushl %edx
movl %eax, 4(%esp) # ??? WHY NOT: pushl %eax
movl -8(%ebp), %eax # ??? WHY NOT: pushl -8(%ebp)
movl %eax, (%esp)
call athena
movl %eax, f
我猜这段代码试图为函数调用推送 3 个参数。但是为什么不使用pushl。这段代码的用途是什么?它是如何工作的?
【问题讨论】:
-
我不知道为什么会这样。也许是因为代码类似于通过寄存器传递参数的 x86-64? (例如,它们只有一个“将值加载到..”指令)。另外,你见过这个问题吗? stackoverflow.com/questions/22267767/…
-
PUSH 是一条遗留指令,在现代内核上执行不佳。它间接依赖于 ESP 寄存器的值。这使得乱序执行变得困难。 MOV没有这样的问题。如英特尔优化手册中所述,编码规则 25。
-
这里有什么遗漏吗?我希望
movels 之前的某个地方是sub %esp,xxx,其中xxx是要传递的参数的大小?然后当电话返回时,不久之后,add %esp,xxx? -
还要注意它不是“低于堆栈指针”它实际上是在上面。 gcc 有控制这种行为的选项,参见手册中的
-mpush-args和-maccumulate-outgoing-args。他们也在那里给出了一些解释。
标签: assembly x86 32-bit disassembly gnu-assembler