2

Im trying to program a function to use extra arguments besides 4 (since my version of mips only supports $a0-$a3) by pushing them on the stack, but my code is incorrect. Here is my code in main (snippet):

li $t0,40 #temp value for our 5th arg.

addi $sp, $sp, -4 #decrement stack pointer by 4
sw $t0, 0($sp) #save the value of $t0 on the stack.

jal printf

which sets a temporary value of 40, gives space on the stack, and saves it. My function is then called. As a test to see if this worked, inside the function when i move these temp arguments $a0-$a3 to their saved register counterparts, I have this code:

lw $t0, 0($sp) 
addi $sp, $sp, 4
move $a0,$t0

li $v0, 1
syscall

...but it only prints out a 0 and not 40, so im doing something incorrect. Any help would be greatly appreciated (and upvoted)

Wooble
  • 87,717
  • 12
  • 108
  • 131
jfisk
  • 6,125
  • 20
  • 77
  • 113

3 Answers3

3

In the most common 32 bit MIPS calling convention, space is reserved on the stack for $a0,$a1,$a2 and $a3, so the called function should expect to find the 5th argument at 16($sp).

The easiest way to figure these things out is to write an empty version of your function in C, and dissassemble the .o file to figure out how the arguments are passed by the compiler.

markgz
  • 6,054
  • 1
  • 19
  • 41
  • Why would space be reserved on the stack for arguments that are in registers? The Wikipedia page says that arguments 5 and on are passed on the stack, not 1 through 4. – blackcompe Apr 18 '12 at 20:38
  • 1
    That's just how the calling convention is defined, it does allow the called routine to save its arguments in a known place on the stack. The wiki page is incomplete. See http://www.mips.com/media/files/MD00565-2B-MIPS32-QRC-01.01.pdf. – markgz Apr 18 '12 at 21:24
  • 1
    The calling conventions say to make room on the stack for $a0-$a3 so that if you have call another function, there is place to save the arguments. This can be optimized out is a variety of ways of course, but it is necessary for debuggers to work properly. – D'Nabre Apr 23 '12 at 21:19
  • These days it's even easier to look at compiler output, e.g. on https://godbolt.org/z/ohxaad (MIPS(el) GCC 5.4) calling printf. You could also write a function that takes multiple args and return the subtraction of two of them for example. – Peter Cordes Mar 12 '21 at 05:50
0

That code is absolutely correct, so the problem lies elsewhere. My best guess is that the stack pointer hasn't been managed correctly up to that point in your code or in printf you have an error before popping off the stack. Why not use the debugger to see what's happening? If you can, post a runnable program with all irrelevant code stripped out that demonstrates the problem. Here's a working MIPS program that does what you're trying to do and uses the same instructions.

blackcompe
  • 3,180
  • 16
  • 27
  • http://cl.ly/0D1s2j2y400n2I1n2A1h is the full program. In printf_branch_args I need to calculate the address of my next argument but im unsure how to do that – jfisk Apr 18 '12 at 21:13
  • @jfisk: There's no label named `printf_branch_args`. Anyway, that's a complex piece of code that I can't help you with. My aim was simply to answer the question as presented. – blackcompe Apr 18 '12 at 22:10
0

There's two issues you are dealing with, from looking at the full code you linked above.

1) You're stack isn't being setup properly to use arguments (especially more than four) for the standard MIPS o32 calling conventions. The other answers do a good job of pointing you to help on this.

2) The 'printf' you are using doesn't use standard calling convention whatsoever. If you see the comments:

## printf--
## A simple printf-like function. Understands just the basic forms
## of the %s, %d, %c, and %% formats, and can only have 3 embedded
## formats (so that all of the parameters are passed in registers).
## If there are more than 3 embedded formats, all but the first 3 are
## completely ignored (not even printed).
## Register Usage:
## $a0,$s0 - pointer to format string
## $a1,$s1 - format argument 1 (optional)
## $a2,$s2 - format argument 2 (optional)
## $a3,$s3 - format argument 3 (optional)
## $s4 - count of formats processed.
## $s5 - char at $s4.
## $s6 - pointer to printf buffer

Nothing is expected to be passed on the stack. (Remember $s0-6 aren't stack-related). You can provide to this function $a0-> format string, and 3 arguments (in $a1, $a2, and $a3). Note these comments suggests says it destroys $s0-$s6, though from the incomplete code, I can say how much is restored without tracing through it. In short, this printf you found, might be handy, but it does not use stack conventions you should be learning and it is pretty limited. Assuming you have permission to use it, see about getting permission to modify and just rewrite the interface to something sane. Keep in mind having to call the function multiple times if you need to print out more than 3 variables at a time isn't a big deal (if it is, just write a wrapper).

D'Nabre
  • 2,226
  • 16
  • 13