题
当您将参数传递到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
解决方案
不。
Callee(目标功能)通常不负责删除自己的论点。呼叫者将它们放在那里,并且是最了解如何删除它们的人。
在68000上,很容易使用堆栈中的相对偏移读数,因此无需物理删除(pop)堆栈中的参数。这围绕着必须很好地“双打”返回地址的问题。
因此,您的代码应该阅读类似的内容:
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
其他提示
从某种意义上说,您不会从堆栈中“取下”参数。通常,您将帧寄存器分配给在入口点的堆栈顶部指向该过程的堆栈顶部,并以恒定的(从框架指针)访问已知偏移量的参数。然后您的索引只是“跳过”返回地址,您知道在那里。
例如,在某些假设的组装中,当您正在进行过程时。假设堆栈正在成长:
...
argument2
argument1
ret addr <---- stack pointer
因此,只需访问即可 argument1
在偏移量 sp+4
(假设32位), argument2
在偏移量 sp+8
, 等等。由于这些调用约定是已知的,因此这些偏移在您的代码中进行了硬编码,并且有效地计算。
帧指针非常有用,因为您还将局部变量推向堆叠,并且您不希望参数的索引在不同位置更改,因此帧指针在整个过程的执行过程中都提供了稳定的锚点。
不,无需弹出堆栈即可查看它们。通常的过程是使用@Eli所说的“帧指针”寄存器。实际上,68K甚至有指示(LINK
)旨在促进这一点:(a)保存先前的帧指针,(b)将当前的堆栈指针复制到框架指针,(c)将堆栈指针减少指定金额以留出空间的空间本地变量。
这是一个 C代码和相应的68000汇编程序的示例.
不隶属于 StackOverflow