views:

127

answers:

4

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)

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
+5  A: 

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.

Eli Bendersky
+2  A: 

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.

David Gelhar
A: 

I suppose that you will call this function from some program language. In that case everything is depend of calling convenction! Here you can check kind of x86 calling conventions! Ofcourse you must know what is the default compiler colling convention and/or haw to change it for some program language!

GJ
A: 

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
unwind