Assembly call subprograms based on user input
cmp %esp, '0'
is wrong, because it tries to compare the value of %esp
to the value in memory at address '0'
. At&t syntax uses reversed operands, and it needs a $
prefix for immediates. But you already know this, I guess you were just a little careless. The correct instruction is cmpb $'0', (%esp)
to compare the byte in memory at address %esp
to the ascii code of 0
.
Furthermore, you allocated 4 bytes from the stack, but you never free that. When you eventually hit a ret
it will use your local variable as return address which is of course a bad thing :) A nice trick is to use lea 4(%esp), %esp
to free it without affecting the flags, so you can do this between the cmp
and the jz
. If you like less tricky stuff, you can of course just pop the input into a register and use that in the comparison, such as:
pop %eax
cmp $'0', %al
PS: Learn to use a debugger. That would have pointed you directly at the instruction, and then you probably could have figured out the problem yourself.
Subroutine being being called, but something wrong with arithmetic?
Answer 2, containing reviewed the updated source from OP (after he fixed the problems with original source):
Just adjusted source, how I would expect it to be written:
# register allocation through main code:
# s0 = u, s1 = v, s2 = intermediate/final result
# WARNING: code needs delayed branching ON (like real MIPS CPU)
.text
.globl main
main:
li $v0, 4 # print string syscall method
la $a0, prompt # prints prompt
syscall
# input "u"
li $v0, 4 # print string syscall method
la $a0, prompt1 # prints "u" prompt
syscall
li $v0, 5 # reads the int typed
syscall
move $s0, $v0 # remember "u" input
# input "v"
li $v0, 4 # print string syscall method
la $a0, prompt2 # prints "v" prompt
syscall
li $v0, 5 # reads the int typed
syscall
move $s1, $v0 # remember "v" input
# result = 0
move $s2, $zero
# exit when user did enter pair of zeroes
or $at, $s0, $s1 # binary OR(u, v)
bne $at, $zero, doCalculation # when both inputs are zero -> terminate
li $v0, 10 # nop not needed, v0=10 is harmless in case of calculation
syscall # terminate
doCalculation:
# calculate result += 7*u*u
move $a1, $s0 # a1 = u
move $a2, $s0 # a2 = u
jal arithmetic # jumps to subroutine
li $a0, 7 # load a0 in delayed branching as argument for subroutine
add $s2, $s2, $v0 # update result
# calculate result += -25*u*v
move $a1, $s0 # a1 = u
move $a2, $s1 # a2 = v
jal arithmetic # jumps to subroutine
li $a0, -25 # load a0 in delayed branching as argument for subroutine
add $s2, $s2, $v0 # update result
# calculate result += 63*v*v
move $a1, $s1 # a1 = v
move $a2, $s1 # a2 = v
jal arithmetic # jumps to subroutine
li $a0, 63 # load a0 in delayed branching as argument for subroutine
add $s2, $s2, $v0 # update result
# display result
li $v0, 4
la $a0, prompt3
syscall
li $v0, 1
move $a0, $s2
syscall
li $v0, 4
la $a0, newline
syscall
j main # rinse and repeat until [0, 0] user input
nop # needed, to not execute slow MUL from subroutine
arithmetic:
mul $v0, $a1, $a2
jr $ra
mul $v0, $a0, $v0 # v0 = a0 * a1 * a2
.data
prompt: .asciiz "Type zero for both u and v to end program\n"
prompt1: .asciiz "Please type value for 'u': \n"
prompt2: .asciiz "Please type value for 'v': \n"
prompt3: .asciiz "Result is: "
newline: .asciiz "\n"
Call a subroutine on each character in string - MIPS
You will need to save $a0
and $a1
elsewhere (usually stack) for the duration of the subroutine call. Also, your loop
isn't a subroutine, no reason to call it using jal
. On the other hand, the callback is a subroutine, you should call it using jalr
. Something along these lines should work:
string_for_each:
addiu $sp, $sp, -12 # Need 3 locals for $a0, $a1 and $ra
sw $ra, 0($sp) # Store $ra
sw $a1, 8($sp) # Store $a1
loop:
sw $a0, 4($sp) # Store $a0 as it will be used for argument
lb $t0, 0($a0) # Get current character
beq $t0, $zero, end_for_each # Done when reaching NULL character
jalr $a1 # Call callback subroutine
lw $a0, 4($sp) # Reload $a0
lw $a1, 8($sp) # $a1 could have changed (calling convention)
addi $a0, $a0, 1 # Increment to get next character in string
j loop
end_for_each:
lw $ra, 0($sp) # Reload return address to caller
addiu $sp, $sp, 12 # Free locals
jr $ra
x86 assembly: Pass parameter to a function through stack
Typically, you use the base pointer (bp
on 16 bit, ebp
on 32 bit) to refer to parameters and locals.
The basic idea is that every time you enter into a function you save the stack pointer inside the base pointer, to have the stack pointer at when the function was called as a "fixed reference point" throughout execution of the function. In this schema [ebp-something]
typically is a local, [ebp+something]
is a parameter.
Transposing the typical 32-bit, callee-cleanup calling conventions you can do like this:
caller:
push param1
push param2
call subroutine
subroutine:
push bp ; save old base pointer
mov bp,sp ; use the current stack pointer as new base pointer
; now the situation of the stack is
; bp+0 => old base pointer
; bp+2 => return address
; bp+4 => param2
; bp+6 => param1
mov ax,[bp+4] ; that's param2
mov bx,[bp+6] ; that's param1
; ... do your stuff, use the stack all you want,
; just make sure that by when we get here push/pop have balanced out
pop bp ; restore old base pointer
ret 4 ; return, popping the extra 4 bytes of the arguments in the process
Related Topics
Why Does Script Not Recognize File Extension
How to Read from Text File Line-By-Line and Split the Line by a Character
Using Ssh to Run a Cleartool Command with Agruments on Remote a Linux MAChine
Bash/Linux Sort by 3Rd Column Using Custom Field Seperator
Compute Base64 Encoded Hash from a Given Hash
Why Count Differs Between Ls and Ls -L Linux Command
Stop on Newline When Using Read(...)
G++ Always Fails with Undefined Reference to _Unwind_Getipinfo
Simple Way to Get Filesize in X86 Assembly Language
Safely Remembering Ssh Credentials in Bash Script
How to Mail Script Output in Table Format
How to Find Common Rows in Multiple Files Using Awk
How to Create an Alias in Linux
How to Read from User in Rpm Install Script
Ha Proxy Simple Forwarding with Docker