【发布时间】:2022-07-22 01:34:41
【问题描述】:
在下图中,有一个汇编代码。无论我尝试了多少,我都无法完全理解它是如何工作的。这是我的思考过程: 我假设我输入了 3。
-
mov bp, sp //使bp指针等于sp
-
mov ax, [bp+2]// ax 等于 3。3 存储在 ax bp 上方 2 个地址和 return 上方 1 个地址。
-
cmp a, 1 //3不等于1
-
jz exit // 代码不跳转退出原因3不等于1。
-
push ax // 3 现在在 bp-1
-
十进制 ax // ax=2
-
push ax // ax=2 被推到 bp-2
所以现在我们有了堆栈
return address bp 3 2 -
call func // func 被再次调用
-
add sp, 2 //函数结束后返回地址,sp+2删除变量
代码继续,直到堆栈看起来像这样:
return address
bp
3
2
返回添加sp,2
bp
2
1
返回添加sp,2
bp
现在 ax=1,它会跳到退出。
ret 现在会做什么?进展如何?
我怎么知道是_cdecl还是_stdcall
【问题讨论】:
-
push ax将sp递减 2 而不是 1。ret将返回给调用者。如果递归将在call func之后并继续add sp, 2。对于顶层,它将返回给原始调用者。该函数是_cdecl,因为调用者删除了参数并且代码没有使用ret immediate。 -
你可以说它不是
__stdcall,因为它没有使用ret 2。 arg-passing 是__cdecl,因为它们在堆栈上并被调用者弹出。但是这个函数破坏了 BP 和 BX,所以它也没有完全遵循__cdecl;这些寄存器通常是调用保留的。 en.wikipedia.org/wiki/… 没有在表中提到保留调用和调用破坏的寄存器,并且在 16 位内容中,这与在 32 位中的一致程度较低。之前那篇文章en.wikipedia.org/wiki/X86_calling_conventions#cdecl 提到了regs。 -
你们能否向我解释一下代码是如何工作的。真的会救我。
标签: assembly reverse-engineering x86-16