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.
精彩评论