我有一个程序应该根据用户输入0
或not 0
添加或减去两个硬编码的数字。我在input
中遇到内存访问冲突错误。当我在第9行尝试call sum
或call diff
代替input
时,它可以正常工作,并为我提供预期的输出。 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
进行比较?
答案 0 :(得分:2)
cmp %esp, '0'
错误,因为它会尝试将%esp
的值与地址'0'
的内存中的值进行比较。 At&t语法使用反向操作数,并且它需要$
前缀用于immediates。但你已经知道了,我想你只是有点粗心。正确的指令是cmpb $'0', (%esp)
,用于将地址%esp
的内存中的字节与0
的ascii代码进行比较。
此外,您从堆栈中分配了4个字节,但您永远不会释放它。当你最终命中ret
时它将使用你的局部变量作为返回地址,这当然是一件坏事:)一个很好的技巧是使用lea 4(%esp), %esp
释放它而不影响标志,所以你可以在cmp
和jz
之间执行此操作。如果你喜欢不那么棘手的东西,你当然可以将输入弹出到一个寄存器中并在比较中使用它,例如:
pop %eax
cmp $'0', %al
PS:学习使用调试器。那会直接指向你的指令,然后你可能已经自己想出了问题。