我想知道" CALL"指令执行。它首先在堆栈或函数参数上推送返回地址吗?
由于
答案 0 :(得分:7)
CALL
根本不会推动参数。它只推送返回地址。你有责任自己推动论证,这显然发生在CALL
之前。例如:
push 2
push 1
push "%d"
call printf
next_instruction:
add esp, 12
当进入printf
函数时,假设接近32位的调用,堆栈将如下所示:
esp+0: address of next_instruction
esp+4: address of "%d"
esp+8: 1
esp+12: 2
编辑:关于参数的顺序,扩展了@Martin所说的内容:
对堆栈中的内容的解释是调用者和被调用者之间的契约(名为'调用约定'),它取决于很多东西,包括语言,架构,编译器等。对于x86上的C,参数从最后一个推送到第一个。所以上面的汇编代码段对应于翻译的C语句:
printf("%d", 1, 2);
如果你看一下上面的堆栈,你会看到,因为我们按相反的顺序推送了参数,所以它们从第一个到最后一个相对于esp
被排序。这种方式printf
可以读取第一个参数"%d"
,而不知道将跟随多少参数,然后从格式字符串中确定其余参数。此外,因为在C调用约定中,调用者负责从堆栈中删除参数(next_instruction
),传递多于必要的参数是无害的(尽管根据标准它是未定义的行为)。
答案 1 :(得分:2)
如果函数返回的对象太大而无法放入寄存器,则预先分配返回对象的空间:
sub esp,sizeof object
push ecx
push eax
call example
add esp,8 ;restore stack
; ;esp is now pointer to object
add esp,sizeof object ;restore stack once object no longer needed