根据用户输入汇编调用子程序

时间:2015-03-12 12:50:24

标签: linux assembly input x86 att

我有一个程序应该根据用户输入0not 0添加或减去两个硬编码的数字。我在input中遇到内存访问冲突错误。当我在第9行尝试call sumcall diff代替input时,它可以正常工作,并为我提供预期的输出。 loopnext用于显示堆栈的结果。

.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 个答案:

答案 0 :(得分:2)

cmp %esp, '0'错误,因为它会尝试将%esp的值与地址'0'的内存中的值进行比较。 At&t语法使用反向操作数,并且它需要$前缀用于immediates。但你已经知道了,我想你只是有点粗心。正确的指令是cmpb $'0', (%esp),用于将地址%esp的内存中的字节与0的ascii代码进行比较。

此外,您从堆栈中分配了4个字节,但您永远不会释放它。当你最终命中ret时它将使用你的局部变量作为返回地址,这当然是一件坏事:)一个很好的技巧是使用lea 4(%esp), %esp释放它而不影响标志,所以你可以在cmpjz之间执行此操作。如果你喜欢不那么棘手的东西,你当然可以将输入弹出到一个寄存器中并在比较中使用它,例如:

pop %eax
cmp $'0', %al

PS:学习使用调试器。那会直接指向你的指令,然后你可能已经自己想出了问题。