将参数传递给cpu堆栈上的函数时,
你把参数放在然后JSR把返回地址放在堆栈上。 这意味着在您的函数中,您必须获取堆栈的顶部项(返回地址) 在你可以把其他人带走之前)
返回值按惯例存储在寄存器D0
中。
例如以下是正确的方法:
...
|Let’s do some addition with a function,
MOVE.L #4, -(SP)
MOVE.L #5, -(SP)
JSR add
|the result of the addition (4+5) is in D0 (9)
...
add:
MOVE.L (SP)+, A1 |store the return address
|in a register
MOVE.L (SP)+, D0 |get 1st parameter, put in D0
MOVE.L (SP)+, D2 |get 2nd parameter, put in D2
ADD.L D2, D0 |add them,
|storing the result in D0
MOVE.L A1, -(SP) |put the address back on the
|Stack
RTS |return
答案 0 :(得分:8)
您不会从堆栈中“取消”参数,因为您不会弹出它们。您通常会在程序的入口点指定一个帧寄存器指向堆栈的顶部,并从帧指针的常量已知偏移量访问参数。然后你的索引只是“跳过”你知道的返回地址。
E.g。在一些假设的集会中,当你在一个程序中。假设堆栈正在增长:
...
argument2
argument1
ret addr <---- stack pointer
所以只需在偏移argument1
(假设为32位),sp+4
偏移argument2
等处访问sp+8
,等等。由于这些调用约定是已知的,因此这些偏移量是在您的代码中进行硬编码,并且计算效率很高。
帧指针非常有用,因为您还将局部变量推送到堆栈,并且您不希望在不同位置更改参数索引,因此帧指针在整个过程执行期间提供稳定的锚点。 / p>
答案 1 :(得分:6)
没有
被调用者(目标函数)通常不负责删除自己的参数。呼叫者把它们放在那里,并且是最了解如何移除它们的人。
在68000上,使用堆栈中的相对偏移量很容易读取,不需要从堆栈中物理删除(弹出)参数。这解决了必须非常好地“双缓冲”返回地址的问题。
所以,你的代码应该是这样的:
MOVE.L #4, -(SP)
MOVE.L #5, -(SP)
JSR add
ADDQ.L #8, SP |remove the arguments from the stack, both at once.
...
add:
MOVE.L 4(SP), D0 |get 1st parameter, put in D0
ADD.L 8(SP), D0 |add the 2nd parameter
RTS |return
答案 2 :(得分:3)
不,没有必要从堆栈中弹出参数来查看它们;通常的程序是使用“帧指针”寄存器,如@eli所说。事实上,68k甚至有一条指令(LINK
),它旨在促进:它是一条指令,(a)保存前一帧指针,(b)将当前堆栈指针复制到帧指针,以及(c)将堆栈指针递减指定的量,以便为局部变量留出空间。
这是一个example of C code and the corresponding 68000 assembler。