在堆栈上传递参数

发布于 2024-08-28 01:41:55 字数 773 浏览 4 评论 0原文

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

When you pass parameters to a function on the cpu stack,

You put the parameters on then JSR puts the return address on the stack.
So that means in your function you must take the top item of the stack (the return address)
before you can take the others off)

The return value is stored by convention in register D0.

eg is the following the correct way to go about it:

...
|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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

画▽骨i 2024-09-04 01:41:56

不。

被调用者(目标函数)通常不负责删除自己的参数。调用者将它们放在那里,并且是最知道如何删除它们的人。

在 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

No.

The callee (the target function) is generally not responsible for removing its own arguments. The caller put them there, and is the one who best knows how to remove them.

And on the 68000, it's easy to read using a relative offset into the stack, there's no need to physically remove (pop) the arguments from the stack. This goes around the problem of having to "double-buffer" the return address quite nicely.

So, your code ought to read something like this:

    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
北恋 2024-09-04 01:41:56

不,不需要从堆栈中弹出参数来查看它们;通常的过程是使用“帧指针”寄存器,如 @eli 所说。事实上,68k 甚至有一条指令 (LINK) 旨在促进这一点:它是一条指令,(a) 保存前一个帧指针,(b) 将当前堆栈指针复制到该帧指针,并且 (c) 将堆栈指针递减指定的量,以为局部变量留出空间。

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

No, there's no need to pop parameters off the stack to look at them; the usual procedure is to use a "frame pointer" register as @eli says. In fact, the 68k even has an instruction (LINK) that's designed to facilitate that: it's a single instruction that (a) saves the previous frame pointer, (b) copies the current stack pointer to the frame pointer, and (c) decrements the stack pointer by a specified amount to leave room for local variables.

Here's an example of C code and the corresponding 68000 assembler.

你在看孤独的风景 2024-09-04 01:41:55

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

例如,在某个假设的装配中,当您正在进行手术时。假设堆栈向下增长:

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

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

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

You do not "take off" parameters from the stack, in the sense that you don't pop them. You usually assign a frame register to point to the top of the stack at the entry point to the procedure, and access the parameters at constant, known offsets from the frame pointer. Then your index just "skips" the return address, which you know is there.

E.g. in some hypothetical assembly, when you're in a procedure. Suppose stack is growing down:

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

So just access argument1 at offset sp+4 (assuming 32-bit), argument2 at offset sp+8, etc. Since these calling conventions are known, these offsets are hard-coded in your code and are efficient to compute.

The frame pointer is very useful since you also push the local variables to stack, and you wouldn't want indexing of parameters to change in different places, so the frame pointer provides a stable anchor throughout the execution of the procedure.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文