4

当您将参数传递给 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
4

3 回答 3

8

您不会从堆栈中“取出”参数,因为您不会弹出它们。您通常分配一个帧寄存器以指向过程入口点的堆栈顶部,并以常量访问参数,已知帧指针的偏移量。然后你的索引只是“跳过”你知道的返回地址。

例如,在一些假设的装配中,当你在一个程序中时。假设堆栈正在向下增长:

...
argument2
argument1
ret addr     <---- stack pointer 

因此,只需argument1在 offset sp+4(假设为 32 位)、argument2在 offsetsp+8等处访问。由于这些调用约定是已知的,因此这些偏移量在您的代码中是硬编码的,并且计算效率很高。

帧指针非常有用,因为您还将局部变量压入堆栈,并且您不希望参数的索引在不同的地方发生变化,因此帧指针在整个过程的执行过程中提供了一个稳定的锚点。

于 2010-04-09T05:33:29.140 回答
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
于 2010-04-09T12:15:41.653 回答
3

不,不需要从堆栈中弹出参数来查看它们;通常的程序是使用@eli 所说的“帧指针”寄存器。事实上,68k 甚至有一条指令LINK(堆栈指针按指定数量为局部变量留出空间。

这是C 代码和相应的 68000 汇编程序的示例

于 2010-04-09T05:41:50.350 回答