Assembly call subprograms based on user input

2019-03-05 17:41发布

问题:

I have a program that is supposed to either add or subtract two hardcoded numbers based on user input 0 or not 0. I get memory access violation error inside input. when i try to call sum or call diff instead input in line 9 it works fine and gives me expected output. loop and next is used to display result from stack.

.text

.global _start

_start:

xorl %esi, %esi     # zerowanie licznika

call input          #  <----  line 9

loop:               # label
movl $0, %edx       # reszta z dzielenia
movl $10, %ebx      # dzielnik
divl %ebx           # dzielenie, wynik w eax, reszta w edx
addl $48, %edx      # kod ASCII
pushl %edx          # edx na stos
incl %esi           # esi++
cmpl $0, %eax       # porównaj wynik i 0
jz   next           # jeśli koniec, jump next
jmp loop            # jeśli nie, następna iteracja

next:               # label
cmpl $0, %esi       # porównaj licznik z 0
jz   exit           # jeśli koniec, jump exit
decl %esi           # esi--
movl $4, %eax       # kod 4 = zapis
movl %esp, %ecx     # znak do wypisania
movl $1, %ebx       # domyślny strumień - sys_out
movl $1, %edx       # długość stringa do wypisania? 
int  $0x80          # przerwanie
addl $4, %esp       # 
jmp  next           # kolejna iteracja

exit:
mov $1, %eax        # zakończenie programu
mov $0, %ebx        # kod wyjścia
int $0x80           # przerwanie


# ---------------- subprogram ----------------------

input:
movl $3, %eax          # code 3 = input
movl $0, %ebx          # code 0 = stdin
subl $4, %esp          # move stack pointer by 4 bytes
movl %esp, %ecx        # set reading position onto stack
movl $4, %edx          # read 4 bytes
int  $0x80             # interrupt to execute above

cmp %esp, '0'          # if(input == '0') sum else diff
jz sum                 
jnz diff
ret

sum:
movl $37, %eax      # pierwsza liczba sumy
movl $22, %ebx      # druga liczba sumy
addl %ebx, %eax     # suma, wynik w eax
ret

diff:
movl $37, %eax      # pierwsza liczba sumy
movl $22, %ebx      # druga liczba sumy
subl %ebx, %eax     # roznica, wynik w eax
ret

# -------------     end    -------------

How can I edit my input function to read a character/number and compare it to 0?

回答1:

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.