在cdecl
调用约定中,它指出:
Arguments are pushed in the reverse order (right to left)
我的问题是:相对于什么非反向顺序相反?是相对于函数文档的吗?因此,例如,如果我有以下函数文档:
void __cdecl foo (int arg1, int arg2, int arg3)
那么我是否应该只查看函数文档中参数的顺序并反转推送到堆栈上的增强?
第一个函数参数在 asm 指令顺序和执行顺序方面被推到最后。 但是,由于堆栈向下增长,因此第一个参数的地址最低。
这种方案意味着第一个参数(和第二个等)始终可以作为当前堆栈指针的常量偏移量进行访问 - 它位于返回地址之后。
是的,你应该完全按照你在问题末尾的建议去做,尽管一种常见的技术是在函数头的堆栈上保留空间,该空间足够大以支持所有堆栈变量以及任何必需的函数调用参数(但不是返回地址),并且简单地做堆栈相对存储来设置参数。
请注意,在许多 ISA ABI 中,前几个参数是在寄存器中传递的,而不是在堆栈上传递的,但无论如何都会保留堆栈空间,以便跨嵌套函数调用进行可能的存储。
如果您的函数调用是:
foo( arg1, arg2, ... argN )
那么"参数顺序"将从左到右(arg1 到 argN)。 函数调用代码将是:
push arg1
push arg2
...
push argN
call foo
"反向顺序(从右到左)"将是 argN 到 arg1:
push argN
...
push arg1
call foo
当然,参数可能不是单个 DWORDS,因此推送操作可能不是单个指令。 编译器也可能非常聪明,为参数预分配堆栈空间,然后通过各种 MOV 指令完成填充参数,以偏移分配的堆栈空间,可能不按任何特定顺序。 因此,根据"好像"推送已经完成的想法来解释"推送参数"。