如何解决为什么加到 esp 的是 0x10?
我正在阅读一篇 Wikipedia 文章,但在理解以下代码块末尾为何出现 add esp,0x10
时遇到问题。我会保留我自己的假设并简单地问 - 为什么?
printnums:
; stack setup
push ebp
mov ebp,esp
sub esp,0x08
mov [ebp-0x04],ecx ; in x86,ecx = first argument.
mov [ebp-0x08],edx ; arg2
push [ebp+0x08] ; arg3 is pushed to stack.
push [ebp-0x08] ; arg2 is pushed
push [ebp-0x04] ; arg1 is pushed
push 0x8065d67 ; "The numbers you sent are %d %d %d"
call printf
; stack cleanup
add esp,0x10
nop
leave
retn 0x04
解决方法
这里没有意义,因为 leave
将恢复 ESP 当前指向的任何位置。
正如维基百科所说,这是从其正上方显示的 C 函数的 GCC 输出的反汇编
(https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_fastcall)。我们可以从 __attribute__((fastcall))
看出它不是 MSVC,nop
和 leave
看起来像未优化的 GCC 输出。
这就是为什么在使用 push
重新加载它们之前,它将 2 个传入寄存器参数存储到堆栈空间。
函数调用语句本身的代码块以弹出实际传递给 printf 的 4 个双字参数(即 cdecl,而不是 fastcall)结束。那是 0x10 = 16 个字节。
它不会弹出 sub esp,8
为本地变量保留的空间;剩下 leave
。
您可以在 Godbolt 编译器资源管理器 (https://godbolt.org/z/vdM4cxM7q) 上看到相同的内容,并且通过查看编译器 asm 输出(而不是反汇编),您可以获得符号名称,而不是像 0x8065d67 这样的数字地址。更重要的是,它会用颜色突出显示 C 源代码行,使它们与汇编行匹配。
(实际 gcc -O0 -m32
输出使用 sub esp,24
,而不是 8。也许维基百科的输出来自更早的 GCC 版本。或者它来自面向 Windows 或 *BSD 的 GCC 版本,其中 16 字节堆栈对齐不是 32 位代码的要求;似乎浪费空间的错误随着 -mpreferred-stack-boundary=2
消失了,所以 GCC5.4 https://godbolt.org/z/KWzK6zdrj 完全重现了 asm 输出。GCC 4.9 及更早版本没有带有 NOP 的废弃说明。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。