什么是参数推送顺序?

14

我正在学习汇编语言。什么是参数推送顺序?我知道这是如何将参数推送到堆栈中,但是“左侧”和“右侧”的含义是什么?相对于什么的左侧或右侧?

还是这只与命令的语义书写方式有关,例如:

mov ebp, esp             ;esp is moved into ebp, right to left.

这样正确吗?或者有人能给我解释一下吗?

2个回答

19
处理器并不知道'函数参数'。因此,当您想编写f(a,b,c)时,您确实需要将参数'推一些地方'。
如何在哪里推它们只是惯例。我知道在大多数x86机器上,函数参数从右到左按顺序推送到堆栈上,即先c,然后b,最后a。
push c
push b
push a
call f

在x86上,将数据压入栈会使栈顶减少一个字。已经压入了三个字和返回地址,因此被调用的函数可以使用top + 1*W表示参数a,使用top + 2*W表示参数b,使用top + 3*W表示参数c

你也可以约定:前两个参数放在寄存器ebxecx中,其余参数放在栈中。只要调用者和被调用者达成一致,就可以正常运行。


2
ebx-1 是从哪里来的?如果它们应该是地址,那么 push 指令会将栈指针减去 4(在 64 位模式下为 8),所以每个栈槽之间相隔 4 或 8 个字节,例如 ebx - 4(c)、ebx - 8(b)等。而且这只有在 EBX = ESP 的情况下才成立。这很不寻常;如果你要使用任何寄存器进行操作,那么应该使用 EBP。但是 被调用者 f 不能假设调用者相对于其传入的堆栈参数在哪里留下了 EBP。它需要查看其返回地址上方的内容,以及 [esp+4](a)、[esp+8](b)等更高的偏移量。或者在推送任何内容后使用更高的偏移量。 - Peter Cordes
但是,是的,你最后一段话是正确的,寄存器调用约定可以工作,例如fastcall将参数传递到ECX、EDX,或者gcc的regparm(3)将参数传递到EAX、EDX、ECX。而你之前提到的关于将第一个参数推入栈顶的做法也是正确的,这样它就在最低地址处。 - Peter Cordes
谢谢,你说得对。我应该把它留在更高的层面上。 - xtofl
1
这在一定程度上解决了问题,但是 c 的地址比 a 更高,因为它先被推入了堆栈,而两个推入操作之后进行了两次 stack_pointer-=stack_width。帧指针指向的标准位置是返回地址的正下方,此时 a 的地址应该是 frame + 2*Wb 的地址应该是 frame + 3*W。但是不管你的参考点在哪里,c 的地址都比较高,加上更多的值而不是减少。 - Peter Cordes
天啊 ;(. 我猜把 W 定义为 -4 是不寻常的... 自己记住:开始一个编译器后端的业余项目。 - xtofl

13

除了xtofl的解释,您可能还想查看这个x86调用约定表。关于参数顺序,您会注意到几乎所有的参数都是从右到左推送的(最右边的参数先被推送),除了Pascal。

xtofl没有涵盖的另一种情况是寄存器参数-一些ABI要求某些参数在寄存器中,而不是在堆栈中。例如,在x86_64系统上,函数:

int add3(int a, int b, int c)

将放置参数:

a -> rdi
b -> rsi
c -> rdx

具体来说,这将看起来像(Intel syntax):

mov     rdi, [source-of-a]
mov     rsi, [source-of-b]
mov     rdx, [source-of-c]
call    add3

所以寄存器从左到右填满,然后栈从右到左使用。

正如xtofl所说,只要调用者和被调用者达成一致,你做什么并不重要 - 显然,如果调用者和被调用者意见不合,那将导致不兼容的问题,这实际上不仅是汇编语言的问题,也是高级语言的问题 - 幸运的是,编译器主要是从右到左操作。如果想进一步了解,你可能会对清理栈的被调用者/调用者感兴趣 - 注意在x86_64中它是如何标准化为一种方法的。

你没有提到你使用的是x86 - 你的架构肯定有一个标准的调用约定,因为没有它很难工作。


1
非常感谢你们两位,你们的帮助非常有用,现在我对它的理解更加深刻了!万分感谢!! - Axolotl
请参阅What are the calling conventions for UNIX & Linux system calls (and user-space functions) on i386 and x86-64,了解32位和64位Linux(以及其他非Windows x86-64系统)的x86调用约定的详细信息。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接