2010-04-09 100 views
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 

回答

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 
8

你不从栈“起飞”的参数,因为你不弹出他们的感觉。您通常会指定一个帧寄存器指向过程入口点处的堆栈顶部,并从帧指针以恒定的已知偏移量访问参数。然后,您的索引只是“跳过”返回地址,您知道该地址在那里。

E.g.在一些假设的程序集中,当你在一个程序中。假设堆栈增长了下来:

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

所以只要访问argument1在偏移sp+4(假设32位),argument2在偏移sp+8,等等。由于这些调用约定是已知的,这些偏移硬编码在你的代码并且计算效率很高。

帧指针非常有用,因为您也将局部变量推入堆栈,并且您不希望索引参数在不同位置更改,因此帧指针在整个过程的执行过程中提供了稳定的锚点。

3

不,不需要从堆栈中弹出参数来查看它们; @eli说,通常的做法是使用“帧指针”寄存器。实际上,68k甚至有一个指令(LINK),它被设计用来实现这一点:它是一个单指令,它可以:(a)保存前一帧指针,(b)将当前堆栈指针复制到帧指针,以及(c)递减指定量的堆栈指针为局部变量留出空间。

这是example of C code and the corresponding 68000 assembler