当您将参数传递到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汇编程序的示例.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top