Mips Procedure: Infinite for loop and Exception occurred at PC - exception

Seeing the topics on the site, however I was not able to solve my problem. I noticed that the code inside the procedure falls into an infinite for and in QTSpim I saw that the registers involved are $s0, $s1, $t2, and $t4.
After a few cycles then the message Exception occurred at PC then expection 7 Bad data address.
Here is the code, I can not figure out where mistake, I tried to write it without procedure and it works perfectly.
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
.text
.globl main
Delete_space:
addi $sp, $sp, -16
sw $s0, 0($sp)
sw $s1, 4($sp)
add $t8, $a0, $zero
lenght_string:
lb $t0, 0($t8)
beqz $t0, for #t8 contain the lenght of string
add $t8, 1
j lenght_string
for:
add $s0, $zero, $zero #i=0
add $s1, $zero, $zero #j=0
condition:
slt $t1, $s0, $t8 #i< lenght_string
beq $t1, $zero, endfor
consequence:
add $t2, $t8, $s0
lb $t3, 0($t2)
bne $t3, ' ', op1
beq $t3, ' ', else
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
op1:
add $t4, $a1, $s1
sb $t3, 0($t4)
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
else:
sub $s1, $s1, 1
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
endfor:
#end
lw $s1, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 16
jr $ra
main:
la $a0, string
la $a1, string2
jal Delete_space
la $a0, string2
li $v0, 4
syscall
li $v0, 10
syscall

I think you're trying to copy characters from one string to the other, skipping spaces. (Maybe that's not what you're trying to do - unfortunately, I don't have time to trace the code in detail.) I think the problem is that you're copying from your source string into a data area that doesn't belong to you.
Strings aren't handled the same in Assembly as they are in a high-level language. They're nothing but a sequence of bytes - there is no concept of a String that automatically expands to contain what you put in it. And there's no concept of bounds checking.
Look at these string declarations:
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
What you've done is assigned string to a memory address containing the byte value 'H'. The subsequent memory locations contain 'e', 'l', 'l', 'o', ' ', 'S', 'i', 'm', 'o', 'n', '\0'.
Then, you've assigned string2 to a memory address containing the byte value '\0' (a null terminator).
If you write a byte to the memory address pointed to by string2, it would replace the null terminator. (You would already be in trouble at this point, because the syscall wouldn't know where your string ends.) If you then write another byte to the memory address pointed to by string2 + 1, you are now writing to memory that you didn't allocate to string2. It might belong to some other variable that's being stored - in which case, you just overwrite what was there before. That's a "buffer overflow", and it's how poorly-written programs such as Internet Explorer get exploited by hackers.
If I'm interpreting the purpose of your program correctly, you need to create a buffer for your output that's big enough to hold it. Something like this would work, assuming your output will never be longer than your input:
.data
string: .asciiz "Hello Simon"
string2: .asciiz "xxxxxxxxxxx"

Related

Why am I getting a duplicate main label error? Also why is there no output?

I am working on my first project in mips, trying to print the sum of all the positive numbers in an array. I am now testing my code with QtSpim and have been getting an error saying I am using the main label twice even though there is only one occurrence. There is also no output, regardless of whether or not I include the main label. Here's the code:
.data
A: .word -89, 19, 91, -23, -31, -96, 3, 67, 17, 13, -43, -74
.text
main:
addi $s0, $zero, 0 #set $s0 for sum of positive nums to 0
la $s1, A #set $s1 to array address
addi $t0, $s1, 48 #set $t0 to exit point
while:
beq $s1, $t0, end
lw $t1, A($s1)
slt $t2, $t1, $zero
bne $t2, $zero, else #skips addition step if A at $s1 is negative
add $s0, $s0, $t1
else:
addi $s1, $s1, 4
j while
end:
li $v0, 1
move $a0, $s0
syscall
li $v0, 10
syscall
Sorry if this is bad formatting for mips, I have only ever worked with Java and C++.
there's an error on this line
lw $t1, A($s1)
What I believe you want is
lw $t1, 0($s1)
A positive integer must be in the offset of the lw instruction.
The main label error seems like a rabbit hole as you see no label was used more than once.

Trouble with simple Mips function

Attempting to write a Mips function with parameters $a0 - (addr) str, $a1 - (int) n that returns the addr of the string that's the last Length - n of the input str.
However I'm getting unwanted results and fear an infinite loop or logical errror. This is what I've got so far...
.globl suffix
suffix:
li $t0, 0 #sets $t0 to 0
jal length #length is another function that sets $v0 to the length of the
input string, pretty sure it works
li $t1, 0
add $t1, $t1, $v0
sub $t1, $t1, $a1
lb $v0, ($a0)
other_loop:
beq $t1, $t0, other_exit
sb $v0, ($a0)
addi $t0, $t0, 1
addi $a0, $a0, 1
j other_loop
other_exit:
jr $ra
I'm worried I'm incorrectly calling my Length function(which sets $v0 to the length of the input str $va0
-Any feedback would be much appreciated.

Strncpy in MIPS has a weird behavior

Here's my code for strncpy. In theory it should work, but when I run tests on it it gives out garbage.
Arguments:
$a0 = pointer to destination array
$a1 = source string
$a2 = number of characters to copy
Returns: the destination array
strncpy:
beqz $a2, out
lb $t0, 0($a1) #load byte
beqz $t0 out
subiu $a2, $a2, 1
sb $t0, 0($a0)
addiu $a0, $a0, 1
addiu $a1, $a1, 1
j strncpy
out:
lb $0 0($a0)
move $v0 $a0
jr $ra
coppy original address of destination array ($a0) and load it in "out:" in $a0->$v0. (in your version you would always get the char behind the last insert... in addition to the above mentioned problem in out:)
addi $a3 $a0 0
strncpy:
(...)
out:
move $a0 $a3
move $v0 $a0

MIPS debugging help

It seems that my understanding of MIPS fails me.
What I need to do is create a program that reverses a string input from terminal, using a stack, but without using $sp. Is there anyone here that knows MIPS?
Register usage
t0 - theString address start
t1 - stack address start
t2 - temp for retrieved character
t3 - counter for t0
t4 - counter for stack
t5 - newline
t6 - Length
.data
theString: .space 42
newLine: .asciiz "\n"
stack: .space 42
.globl main
.text
main:
li $v0, 8 # Set to read string
la $a0, theString
li $a1, 42 # Set size of string
syscall # Read string from terminal
la $t0, theString # Prepare t0 with theString
la $t1, stack # Prepare t1 with stack
la $t5, newLine
addi $t3, $t0, 0
addi $t4, $t1, 42
j push
push:
addi $t3, $t3, 1
addi $t4, $t4, -1
lb $t2, ($t3)
beq $t2, $t5, epush
sb $t2, ($t4)
j push
epush:
sub $t6, $t3, $t0
addi $t6, $t6, -1
addi $t3, $t0, 0
addi $t4, $t1, 0
j pop
pop:
addi $t3, $t3, 1
addi $t4, $t4, 1
lb $t2, ($t4)
beq $t2, $t5, epop
sb $t2, ($t3)
j pop
epop:
addi $t3, $t3, 1
sb $t5, ($t3)
li $v0, 4 # Set to print string
la $a0, theString # Set var to syscall output register
syscall # Print string
li $v0, 10 # Set to end program
syscall # End Program
For example, this just gives an infinite loop. (Sorry for lack of comments, I'm just tearing my hair out here)
Now, I think the problem is somewhere related to the newline character, but I don't know where?
Is there a reason you are using j and not jal? And it appears you are using SPIM, which has numerous issues.
In your pop loop, you are comparing (in beq) the address of newline (in $t5) and the address of the next character in the string. Even though they might contain the address of a location that contains "\n", the addresses might not be the same, because "\n" can be in more than one place. In fact, I can guarantee that they will never be the same, because one will refer to the address of the captured string, and the one in $t5 will be the address of the one at the beginning of the program.

MIPS: removing non alpha-numeric characters from a string

I'm in the process of writing a program in MIPS that will determine whether or not a user entered string is a palindrome. It has three subroutines which are under construction.
Here is the main block of code, subroutines to follow with relevant info:
.data
Buffer: .asciiz " " # 80 bytes in Buffer
intro: .asciiz "Hello, please enter a string of up to 80 characters. I will then tell you if that string was a palindrome!"
.text
main:
li $v0, 4 # print_string call number
la $a0, intro # pointer to string in memory
syscall
li $v0, 8 #syscall code for reading string
la $a0, Buffer #save read string into buffer
li $a1, 80 #string is 80 bytes long
syscall
li $s0, 0 #i = 0
li $t0, 80 #max for i to reach
la $a0, Buffer
jal stripNonAlpha
li $v0, 4 # print_string call number
la $a0, Buffer # pointer to string in memory
syscall
li $s0, 0
jal findEnd
jal toUpperCase
li $v0, 4 # print_string call number
la $a0, Buffer # pointer to string in memory
syscall
Firstly, it's supposed to remove all non alpha-numeric characters from the string before hand, but when it encounters a character designated for removal, all characters after that are removed.
stripNonAlpha:
beq $s0, $t0, stripEnd #if i = 80 end
add $t4, $s0, $a0 #address of Buffer[i] in $t4
lb $s1, 0($t4) #load value of Buffer[i]
addi $s0, $s0, 1 #i = i + 1
slti $t1, $s1, 48 #if ascii code is less than 48
bne $t1, $zero, strip #remove ascii character
slti $t1, $s1, 58 #if ascii code is greater than 57
#and
slti $t2, $s1, 65 #if ascii code is less than 65
slt $t3, $t1, $t2
bne $t3, $zero, strip #remove ascii character
slti $t1, $s1, 91 #if ascii code is greater than 90
#and
slti $t2, $s1, 97 #if ascii code is less than 97
slt $t3, $t1, $t2
bne $t3, $zero, strip #remove ascii character
slti $t1, $s1, 123 #if ascii character is greater than 122
beq $t1, $zero, strip #remove ascii character
j stripNonAlpha #go to stripNonAlpha
strip:
#add $t5, $s0, $a0 #address of Buffer[i] in $t5
sb $0, 0($t4) #Buffer[i] = 0
#addi $s0, $s0, 1 #i = i + 1
j stripNonAlpha #go to stripNonAlpha
stripEnd:
la $a0, Buffer #save modified string into buffer
jr $ra #return
Secondly, it is supposed to convert all lowercase characters to uppercase.
toUpperCase:
beq $s0, $s2, upperEnd
add $t4, $s0, $a0
lb $s1, 0($t4)
addi $s1, $s1, 1
slti $t1, $s1, 97
#beq $t1, $zero, upper
slti $t2, $s1, 123
slt $t3, $t1, $t2
bne $t1, $zero, upper
j toUpperCase
upper:
add $t5, $s0, $a0
addi $t6, $t6, -32
sb $t6, 0($t5)
j toUpperCase
upperEnd:
la $a0, Buffer
jr $ra
The final subroutine, which checks if the string is a palindrome isn't anywhere near complete at the moment. I'm having trouble finding the end of the string because I'm not sure what PC-SPIM uses as the carriage return character.
Any help is appreciated, I have the feeling most of my problems result from something silly and stupid so feel free to point out anything, no matter how small.
Uh, this is a really old question, but the problem is that you're replacing the non-alphanumeric characters with a null character, which terminates the string at that point.
You can find out the value by doing something like this:
syscall to reading a string
mov first value to $2
check the value of $2 with PC-SPIM or a debugger