这是一个可能的汇编代码int x = plus_10(40);
push 40 ; push argument
call plus_10 ; call function
retadd: add esp, 4 ; clean up stack (dummy pop)
; result of the function call is in EAX, per the calling convention
; if compiled without optimization, the caller might just store it:
mov DWORD PTR [ebp-x], eax ; store return value
; (in eax) in x
现在当你打电话时plus_10
, 地址retadd
被压入堆栈call
操作说明。它实际上是一个push
+jmp
, and ret
是有效地pop eip
.
所以你的堆栈看起来像这样plus_10
功能:
| ... |
+--------+
| 40 | <- ESP+4 points here (the function argument)
+--------+
| retadd | <- ESP points here
+--------+
ESP
指向包含返回地址的内存位置。
现在如果你使用pop edx
返回地址进入edx
堆栈如下所示:
| ... |
+--------+
| 40 | <- ESP points here
+--------+
现在如果你执行ret
此时,程序实际上会跳转到地址 40,并且很可能出现段错误或以其他不可预测的方式运行。
编译器生成的实际汇编代码可能有所不同,但这说明了问题。
顺便说一句,编写函数的更有效方法是:对于这个小函数的非内联版本,大多数编译器在启用优化的情况下都会这样做。
global plus_10
plus_10:
mov eax, [esp+4] ; retval = first arg
add eax, 10 ; retval += 10
ret
这比
mov eax, 10
add eax, [esp+4] ; decode to a load + add.
ret