堆栈指针/程序计数器错误MIP

时间:2013-12-03 20:57:22

标签: stack runtime-error mips

这是一个程序的一个功能,可以让你玩公牛和奶牛。 主跳转和指向'guess'标签的链接,然后继续获取正确的输入值。 现在,函数本身运行正常,但是当它完成时我很难让它回到main。 我很确定我已正确设置堆栈指针以确定正确的返回地址,以便在时间上加载到$ ra中,但它仍然给我一个程序计数器错误,并且测试向我显示计数器错误确实当它试图跳回主要时发生。

由于函数调用本身使用了堆栈,我检查确保我在$ sp中从正确的空间加载$ ra(在这种情况下,0($ sp)应该保存main的$ ra),并且它似乎是正确的,但程序计数器错误仍然在运行时出现。

我很感激有关此问题的任何意见!

    #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

2 个答案:

答案 0 :(得分:1)

这里有一些事情。

首先,您使用.word 4来存储input。这会分配一个值为4的单词,这可能不是您想要的。我将其更改为.space 256

接下来,使用系统调用8读取带有5个字符的字符串中的读取。这不起作用,因为正确的输入至少为6个字符,例如:"1234\n\0"

所以,无论如何,你的问题是当你从函数checkAll返回时,你忘记恢复$ra并增加$sp。在分支机构下方无效我将jr $ra更改为:

lw   $ra, 8($sp)
addi $sp, $sp, 8
jr   $ra

这使得执行的 happy 路径在没有特定错误的情况下执行,但是您的程序似乎受到一些概念上的混淆。例如,您将checkAll视为一个函数,方法是使用jal并使用jr进行调用,但在函数的无效情况下,您j直接guess }}。这种不均衡的处理是一场等待的灾难,可能会导致堆栈损坏。

答案 1 :(得分:0)

一个问题是:

checkAll:
addi $sp, $sp, -8     #This function alters the $sp for it's own calls
sw $ra, 8($sp)
sw $a0, 4($sp)

您在堆栈上保留8个字节,但不正确地保存$ra$a0。代码应该是:

addi $sp, $sp, -8     #This function alters the $sp for it's own calls
sw $ra, 0($sp)
sw $a0, 4($sp)

从程序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  

应该是

lw $a0, 4($sp)
lw $ra, 0($sp)
addi $sp, $sp, 8
jr $ra