countstring1.s: Count a string using simple stack frames (but
not yet mips-gcc compliant). This program does follow
the register conventions of pg. 118.
.text
#
register usage:
#
s0: pointer to string
.globl main
main:
addi $sp,
$sp, -8 # claim 2 words
sw $ra, 4($sp) # save ra
sw $s0, 0($sp) # and s0
la $s0, msg #
load address of msg into a0
move $a0, $s0 #
use a0 for arg
jal str_length # takes str in a0,
returns len in v0
move $a0, $v0
ori $v0,$0,1 # syscall 1 for print int with addr in a0
syscall
move $a0, $s0 #
reload str addr from $s0
(preserved across call)
ori $v0,$0,4
# syscall
4 for print string with addr in a0
syscall
lw $s0, 0($sp) # restore s0
lw $ra, 4($sp) # restore ra
addi $sp, $sp, 8
# pop frame
jr $ra # return from main
#
register usage:
#
t0: pointer to string
#
t1: count
#
t2: current byte of string
#
Note this function calls no functions itself, making it a “leaf”
#
As a leaf, it doesn’t need to save and restore $ra
str_length:
move $t0,
$a0 # point to string <-- arg in a0
li
$t1, 0 #
count = 0
loop: lb $t2,
0($t0) # load byte of string
beq $t2, $0, done # check if byte = 0
addi
$t1,$t1,1 # inc count
addi
$t0, $t0, 1 # inc
pointer
j loop # loop back
done: move $v0, $t1
# count to return <--return val in
v0
jr
$ra # return
.data
msg: .asciiz
"Hello, world!"
C program
char str2count[] = "abcdefg";
int main()
{
printf("%d\n", str_length(str2count));
}
int str_length(char
*p)
{
int
i = 0;
for (; *p; p++)
i++;
return i;
}
Result
of mips-gcc –S countstring2.c, converted to SPIM
assembler: caller allocates space for arguments to call on stack, here 1 arg, but rounded up to 4. Caller puts the one arg in a0 (not on the stack, even though there is a spot
reserved for it.) Callee puts it in the stack spot
and then uses it from there.
#
countstring2.s: countstring
using mips-gcc calling convention
.text
.globl main
.globl str_length
main:
addi $sp, $sp, -32 # claim for $ra, $fp, $gp
(2 wds), 4 args for str_length
sw $ra,
28($sp) # save ra
sw $fp,
24($sp) # save fp,
then leave 8 bytes for $gp
move $fp, $sp # fp for this
function
la $a0, msg # load
address of msg into a0
jal str_length # takes str in
a0, returns len in v0
#instead of printf--
move $a0, $v0
ori $v0,$0,1 # syscall 1 for
print int with addr in a0
syscall
lw $fp,
24($sp) # restore fp
lw $ra,
28($sp) # restore ra
addi $sp, $sp, 32 # pop frame
jr $ra # return from main
#
No registers in use except as temporaries (v0 here)
#
stack usage:
#
24($fp): pointer to string (arg 0)
#
8($fp): count (local var)
#
Note this function calls no functions itself, making it a "leaf"
#
As a leaf, it doesn't need to save and restore $ra, only $fp, space for $gp
#
and locals, here count
str_length:
addi $sp, $sp, -24 # claim for $fp, $gp (2 wds), local count, pad
sw $fp,
20($sp) # save caller's fp
move $fp, $sp # establish fp
for this function
sw $a0, 24($fp) # save arg 0 to
spot on stack
sw $0, 8($fp) # init local var
for count
loop: lw $v0, 24($fp) # point to string
lb $v0,
0($v0) # load byte of string
beq $v0, $0, done # check if byte = 0
lw $v0, 8($fp) # count
addiu $v0, $v0,1 # inc count
sw $v0, 8($fp) # store count
lw $v0, 24($fp) # ptr
addiu $v0, $v0,1 # inc ptr
sw $v0, 24($fp) # store ptr
j loop # loop back
done: lw $v0, 8($fp) # load
count for return
lw
$fp, 16($fp) # restore caller's fp
addiu $sp, $sp 24 # pop frame
jr
$ra
# return
.data
msg: .asciiz
"Hello, world!"