基于用户输入的汇编调用子程序

Assembly call subprograms based on user input

我有一个程序应该根据用户输入 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 [=10=], %edx       # reszta z dzielenia
movl , %ebx      # dzielnik
divl %ebx           # dzielenie, wynik w eax, reszta w edx
addl , %edx      # kod ASCII
pushl %edx          # edx na stos
incl %esi           # esi++
cmpl [=10=], %eax       # porównaj wynik i 0
jz   next           # jeśli koniec, jump next
jmp loop            # jeśli nie, następna iteracja

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

exit:
mov , %eax        # zakończenie programu
mov [=10=], %ebx        # kod wyjścia
int [=10=]x80           # przerwanie


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

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

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

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

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

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

如何编辑我的 input 函数以读取 character/number 并将其与 0 进行比较?

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

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

pop %eax
cmp $'0', %al

PS:学习使用调试器。那会直接指向你的说明,然后你可能会自己找出问题。