So I've just started writing x86-64 assembly (AT&T syntax) and this is the code for one of my first assignments. It is a very simple program: it asks for a base and an exponents and it makes the calculation. Unfortunately though, after hours of experimentation, I haven't been able to make it work. It yields correct results if you input 0 as an exponent, but every other time it yields the base value... I used a few breaks in the debugger and it seems that the problem lies at the cmpq %rdx, %rsi
line. No matter what, it yields a TRUE flag and so the execution jumps to the end subroutine immediately... I have no idea what I'm doing wrong, so I would really appreciate some help! I would prefer if you just explained what the problem is, no need to suggest a solution :)
.text
prompt1: .asciz "\n Please enter a non - negative base value. \n"
prompt2: .asciz "\n Please enter a non - negative exponent value. \n"
input: .asciz "%ld"
output: .asciz "\n The result is: %ld \n"
.global main
main:
pushq %rbp #push the value of the old subroutine base pointer to the stack (subroutine prologue)
movq %rsp, %rbp #move the value of the RSP register to the RBP register (both of them now point to the same memory adress, the base of the current subroutine's stack)
movq $0, %rax #necessary to call the printf function
movq $prompt1, %rdi #move the memory address of the prompt1 message to the RDI register (first argument)
call printf #calls printf function - prints the prompt1 message
movq $0, %rax #necessary to call the printf function
movq $prompt2, %rdi #move the memory address of the prompt2 message to the RDI register (first argument)
call printf #calls printf function - prints the prompt2 message
subq $16, %rsp #align the stack for scanf function
movq $0, %rax #necessary to call the scanf function
movq $input, %rdi #move the memory address of the "input" string to the RDI register (first argument)
leaq -16(%rbp), %rsi #move memory address pointed to by the RSP reg to the RSI reg (second argument)
call scanf #calls scanf function - reads base from user and stores it to the memory address on the stack pointed to by the RSI reg
movq -16(%rbp), %rsi #copy the value from the memory address (user input) the RSP reg points towards to the RSI reg
movq %rsi, -8(%rbp) #copy the base value to another memory address in the stack (we will need it in the pow subroutine so we can calculate the final result)
subq $16, %rsp #align the stack for scanf function
movq $0, %rax #necessary to call the scanf function
movq $input, %rdi #move the memory address of the "input" string" to the RDI register (first argument)
leaq -32(%rbp), %rsi #move memory address pointed to by the RSP reg to the RSI reg (second argument)
call scanf #calls scanf function - reads exponent from user and stores it to the memory address on the stack pointed to by the RSI reg
subq $16, %rsp #create more free space in the stack for the counter value while also keeping it 16 - byte aligned
movq $1, -48(%rbp) #move the initial counter to the top of the stack
movq -8(%rbp), %rcx #fourth parameter (copy of base)
movq -48(%rbp), %rdx #third parameter (counter)
movq -32(%rbp), %rsi #second parameter (exponent)
movq -16(%rbp), %rdi #first parameter (base)
call ipow #call ipow subroutine
movq %rcx, %rsi
movq $0, %rax #necessary to call the scanf function
movq $output, %rdi #move the memory address of the "output" string" to the RDI register (first argument)
call printf #calls printf function - prints the output message, but instead of %ld, the final value stored
movq %rbp, %rsp #move the value of the RBP register to the RSP register (both of them now point to the same memory adress, the base of the current subroutine's stack) (subroutine prologue)
popq %rbp #pop the value of the old subroutine base pointer from the stack
call exit #call exit function
ipow:
pushq %rbp #push the value of the old subroutine base pointer to the stack (subroutine prologue)
movq %rsp, %rbp #move the value of the RSP register to the RBP register (both of them now point to the same memory adress, the base of the current subroutine's stack)
cmpq $0, %rsi #compare the exponent in RDX with the literal value 0
jne calc #if not equal (exponent isn't zero) jump to the beginning of the calc subroutine
movq $1, %rcx #if equal, move the literal value 1 (final result) to register RAX
jmp end #jump to the end subroutine
calc:
cmpq %rdx, %rsi #compare the value of the counter in RDX with the value of the exponent in RSI
jge end #if greater or equal end the loop / jump to the beginning of the end subroutine
movq %rcx, %rax
mul %rdi #multiply the value inside the RAX reg with the copy of the base stored in RDI reg --> store low - order bits of the result to RAX reg
movq %rax, %rcx
incq %rdx #increment the counter by 1
jmp calc #jump to beginning of calc subroutine / repeat loop
end:
movq %rbp, %rsp #move the value of the RBP register to the RSP register (both of them now point to the same memory adress, the base of the current subroutine's stack) (subroutine prologue)
popq %rbp #pop the value of the old subroutine base pointer from the stack
ret #when calculations are over, return to the caller subroutine main