开发者

Passing parameters on the stack

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 addr开发者_StackOverflow社区ess
                            |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


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.


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜