2015-03-12 3 views
0

У меня есть программа, которая должна либо добавить, либо вычесть два жестко закодированных номера на основе пользовательского ввода 0 или not 0. Я получаю ошибку нарушения доступа к памяти внутри input. когда я пытаюсь сделать call sum или call diff вместо input в строке 9, он отлично работает и дает мне ожидаемый результат. loop и next Используется для отображения результата из стека.Подпрограммы сборочных вызовов на основе пользовательского ввода

.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 ------------- 

Как я могу изменить свою input функцию, чтобы прочитать символ/номер и сравнить его с 0?

ответ

1

cmp %esp, '0' не так, потому что он пытается сравнить значение %esp со значением в памяти по адресу '0'. В & t синтаксис использует обратные операнды, и для него требуется префикс $. Но вы уже знаете это, я думаю, вы были немного небрежны. Правильная инструкция cmpb $'0', (%esp) для сравнения байт в памяти по адресу %esp с кодом ascii 0.

Кроме того, вы выделили 4 байта из стека, но вы никогда не освободите это. Когда вы в конце концов нажмете ret, он будет использовать вашу локальную переменную в качестве обратного адреса, что, конечно, плохое. Хороший трюк состоит в том, чтобы использовать lea 4(%esp), %esp, чтобы освободить его, не затрагивая флаги, поэтому вы можете сделать это между и jz , Если вы хотите менее хитрый материал, вы можете, конечно, просто поп ввод в регистр и использовать его в сравнении, например, как:

pop %eax 
cmp $'0', %al 

PS: Научитесь использовать отладчик. Это указывало бы вам непосредственно на инструкцию, и тогда вы, вероятно, могли бы сами решить проблему.