I'm currently working on an assignment for class where we have to recursively find the sum of a linked list implemented in MIPS. I get the "bad address in data/stack read in program error at the lw $s0, 0($a0) line. I'm not sure what went wrong, so help would be really appreciated.
llsum:
la $t0, 4($a0)
beqz $t0, return # if next pointer is null, jump to return
jal recurse
# otherwise, iterate through linked list and repeat
recurse:
addi $sp, $sp, -12 # free space (12 bits) on stack
sw $ra, 0($sp) # add return address and s0 to the stack
sw $s0, 4($sp) # storage for current pointer
# sw $a0, 8($sp) # storage for next pointer
lw $s0, 0($a0) # put first four bytes of a0 into s0 (current)
#set a0 (the cell) equal to its next for the iteration
lw $a0, 4($a0)
jal llsum # "sum(n.next)"
sw $v0, 8($sp)
lw $t0, 4($sp)
add $v0, $v0, $t0 # add current to sum (in v0)
lw $ra, 0($sp) # load return address
addi $sp, $sp, 12 # restore stack
jr $ra # return to caller
return:
jr $ra # return to caller
Here's the implementation of the linked list:
.data
listA0: .word -267 listA1
listA1: .word 514 listA2
listA2: .word -927 0
What does the offset represent with the stack pointer? Where is it offset from? The initial location of the stack pointer or the most recent location of the stack pointer. I am trying to step through a program in MARS and trying to trace where the value/register will be placed on the stack and it is not going where I think it should go.
I have been stepping through and things keep getting stored in unexpected locations on the stack.
For example:
addi $t1, $zero, -1
sw $t1, ($sp)
addi $sp, $sp, -24
addi $t2, $zero, -2
sw $t2, ($sp)
addi $t2, $zero, -3
sw $t3, 16($sp)
What is offset 16 "offset" from? Where the stack started out, or the last location of the pointer?
.data
prompt:.asciiz "\nEnter an integer: "
add: .asciiz "\n The sum in decimal is: "
bin: .asciiz "\n The sum in binary is: "
sgt: .asciiz "\n The second integer is greater than the first. "
fgt: .asciiz "\n The first integer is greater than the second."
equal: .asciiz "\n The two entered values are equal: "
.text
main:
li $v0, 4 #print string code
la $a0, prompt #argument
syscall #execute, service print stri
li $v0, 5 # read integer
syscall #v0 gets the returned value
move $s0, $v0 #set v0 -> s0
li $v0, 4
la $a0, prompt
syscall
li $v0, 5
syscall
move $s1, $v0 #set v0 -> s1
add $s2, $s1, $s0 #s2 -> s0 + s1
li $v0, 4 #print string
la $a0, add #argument
syscall
move $a0, $s2
li $v0, 1 #print int
syscall
# Output "sum in binary is:".
la $a0, bin
li $v0, 4
syscall
# Output the binary number. (This is done by isolating one bit
# at a time, adding it to the ASCII code for '0', and outputting
# the character. It is important that the bits are output in
# most-to-least significant bit order.
move $t2, $a0
li $s1, 32 # Set up a loop counter
Loop:
rol $t2, $t2, 1 # Roll the bits left by one bit - wraps highest bit to lowest bit.
and $t0, $t2, 1 # Mask off low bit (logical AND with 000...0001)
add $t0, $t0, 48 # Combine it with ASCII code for '0', becomes 0 or 1
move $a0, $t0 # Output the ASCII character
li $v0, 11
syscall
subi $s1, $s1, 1 # Decrement loop counter
bne $s1, $zero, Loop # Keep looping if loop counter is not zero
slt $t0, $s0, $s1
beq $t0, $0, else
li $v0, 4
la $a0, sgt
syscall
j jump
else:
li $v0, 4
la $a0, fgt
syscall
jump:
li $v0, 10 #system call for exit
syscall
I'm also having quite a bit of trouble getting "the two inputed digits are equal to work. I tried using the three case scenarios and having three separate labels: to send my code to. But it didn't work. I don't know whats going on.
Pretty trivial mistake here.
Look at the line before the loop:
move $t2, $a0
You are clearly attempting to move the sum into $t2 but $a0 contains the address of bin.
Changed this line to:
move $t2, $s2
And everything functions correctly.
This is a function for a part of a program that lets you play Bulls and Cows.
main jumps and links to the 'guess' label and goes on to get the correct input value.
Now, the function itself runs correctly, but I'm having trouble getting it to go back to main when it's done.
I'm pretty sure I've set the stack pointer correctly for the correct return address to main be loaded into the $ra when it's time, but it's still giving me a program counter error, and testing has shown me that the counter error indeed happens when it tries to jump back to main.
Since the function call itself utilizes the stack, I checked to make sure I had the $ra loaded from the right space in $sp (in this case, 0($sp) should hold the main's $ra), and it seems to be correct, but the program counter error still prevails at run time.
I would appreciate any input on this matter!
#Gets user's guess and checks
.data
prompt: .asciiz "\nEnter four unique hexadecimal digits: "
invalidInput: .asciiz "\nInvalid guess: must be four unique hexadecimal digits"
validInput: .byte '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'
input: .word 4
.text
#Get the user input
guess:
addi $sp, $sp, -4 #Here is where I save the return address to main
sw $ra, 0($sp) #
la $a0, prompt
li $v0, 4
syscall
la $a0, input
li $a1, 5
li $v0, 8
syscall
jal checkAll #Jumps to the only other call that affects the $sp
#This is the instruction that is flooping around with my program counter, although it seems right!
lw $ra, 0($sp) #When the function is done, load the return address to main
addi $sp, $sp, 4
jr $ra #jump back to main
#Call to quit - for testing
li $v0, 10
syscall
#Makes room and gets input validated
checkAll:
addi $sp, $sp, -8 #This function alters the $sp for it's own calls
sw $ra, 8($sp)
sw $a0, 4($sp)
li $s0, 3
la $a1, validInput
b isValid
lw $a0, 4($sp) #But then it restores the $sp and is able to link back to the 'guess' call
lw $ra, 8($sp)
addi $sp, $sp, 8
jr $ra
#Checks each character from the input agaisnt the valid input characters, basically if the input is hexadecimal
isValid:
blt $s0, $0, unique
la $t0, ($a0)
add $t1, $s0, $0
add $t2, $t1, $t0
lb $t3, ($t2)
li $s1, 21
#Checks each input character agaisnt each valid input character
checkNum:
blt $s1, $0, invalid
la $t0, ($a1)
add $t1, $s1, $0
add $t2, $t1, $t0
lb $t4, ($t2)
bne $t3, $t4, notEqual
j equal
#Character from input is a valid character
equal:
add $s0, $s0, -1
j isValid
#Character from input is not a valid character
notEqual:
add $s1, $s1, -1
j checkNum
#Check if the input is not duplicated
unique:
la $t0, ($a0)
lb $t1, 0($t0)
lb $t2, 1($t0)
lb $t3, 2($t0)
lb $t4, 3($t0)
beq $t1, $t2, invalid
beq $t1, $t3, invalid
beq $t1, $t4, invalid
beq $t2, $t3, invalid
beq $t2, $t4, invalid
beq $t3, $t4, invalid
jr $ra
invalid:
la $a0, invalidInput
li $v0, 4
syscall
j guess
A few things here.
Firstly, you are using .word 4 to store input. This allocates one word with value 4 which is probably not what you want. I changed this to .space 256.
Next, you use system call 8 to read read in a string with 5 characters. This will not work, as proper input is at least 6 characters, e.g.: "1234\n\0".
So, anyway, your problem here is that when you return from your function checkAll you have forgotten to restore $ra and increment $sp. Below at the branches to invalid I changed jr $ra to:
lw $ra, 8($sp)
addi $sp, $sp, 8
jr $ra
This made the happy path of your execution perform without that particular error, but your program seems to suffer from some conceptual confusion. For example, you treat checkAll as a function by calling it with jal and returning with jr, yet in the invalid case of the function you j straight to guess. This uneven treatement is a waiting disaster and will likely lead to stack corruption.
One problem is this:
checkAll:
addi $sp, $sp, -8 #This function alters the $sp for it's own calls
sw $ra, 8($sp)
sw $a0, 4($sp)
You reserve 8 bytes on the stack, but save $ra and $a0 incorrectly. The code should be:
addi $sp, $sp, -8 #This function alters the $sp for it's own calls
sw $ra, 0($sp)
sw $a0, 4($sp)
The same thing before returning from the procedure checkAll.
lw $a0, 4($sp) #But then it restores the $sp and is able to link back to the 'guess' call
lw $ra, 8($sp)
addi $sp, $sp, 8
jr $ra
Should be
lw $a0, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 8
jr $ra
I am just trying to print this 'a' to screen, but by first pushing to stack so that I can check whether I did accomplish on pushing to stack or not, seems that I couldn't because it prints a weird character everytime. What's wrong?
.data
char: .word 'a'
.text
.globl main
main:
la $t0, char
sub $sp, $sp, 4 #allocate byte for stack
sb $t0, 0($sp) #push to stack
la $t1, 0($sp) #I wasnt able to print the top of the stack directly so I tried this
li $v0, 11
la $a0, 0($t1) #It isnt working anyway.. Prints É
syscall
add $sp, $sp, 4
jr $ra
I am putting my solution after trying the every way that I did to make it work. Still don't have a clue why this one works but, whatever it does.
.data
char: .word 'a'
.text
.globl main
main:
la $t0, char
addi $sp, $sp, -4 #allocate byte for stack
sw $t0, 0($sp) #push to stack
lw $t1, 0($sp) #load from stack
li $v0, 4
la $a0, 0($t1) #It now puts 'a'
syscall
add $sp, $sp, 4
jr $ra