gpt4 book ai didi

assembly - 为什么这段代码在调用函数后两次弹出到同一个寄存器?

转载 作者:行者123 更新时间:2023-12-01 12:27:07 24 4
gpt4 key购买 nike

push EAX
push 8
call malloc
pop EBX
pop EBX
mov [EAX], 0
mov [EAX+4], EBX

为什么我们需要做2次pop EBX? EBX 每次会得到什么值?

最佳答案

基本规则是,无论您插入什么,都必须弹出。否则,您将不平衡堆栈并导致代码崩溃或更糟。该规则意味着您需要弹出与您推送的值相同大小(以字节为单位)的值。

所以在这种情况下,您在调用 malloc 之前将 8 个字节压入堆栈:

push EAX    ; push a DWORD-sized register (4 bytes)
push 8 ; push a DWORD immediate (4 bytes)

要在函数调用后清理栈(malloc需要,因为它使用cdecl调用约定,即caller-cleanup),需要pop 8 个字节。碰巧一个方便的方法是弹出一个寄存器大小的值两次:

pop EBX   ; pop 4 bytes
pop EBX ; pop 4 bytes

栈是LIFO .第一个 pop 将 8 放入 EBX(因为这是您推送的最后一个东西),您并不关心。下一个 pop 将 EAX 的原始值放回 EBX(您压入的第一个东西),稍后您将继续使用它。

如果您不关心保留任何从堆栈弹出的值,您可以简单地使用 ADD 指令,将 8 个字节添加到堆栈指针:

add esp, 8

这可能比两次 pops 稍快,但实际上稍大(3 个字节而不是 2 个字节,as Jester points out)有时优化代码大小与优化代码速度一样重要,因为当代码是更小,更多的可以放入缓存。但在这种情况下,我怀疑更重要的问题是获得被推送的第一个值。由于 malloc 只接受一个参数,第一次推送的唯一原因是保留 EAX 的原始值,因为它被函数调用破坏了(函数在 EAX )。因此,另一种编写代码的方法是:

; Save EAX by moving it into a caller-save register
; (that will not get clobbered by the malloc function).
mov EBX, EAX

; Call the malloc function by pushing a 4-byte parameter and then rebalancing the stack.
push 8
call malloc
add esp, 4

; EAX contains malloc's return value, and EBX contains the original value of EAX
; that we saved before calling malloc.
mov [EAX], 0
mov [EAX+4], EBX

关于assembly - 为什么这段代码在调用函数后两次弹出到同一个寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38246596/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com