循环到第二个方程

looping onto the second equation

我正在制作一个 nasm 86x 的小型计算器,它可以读取形式为

的两行方程

3 + 2

6 / 2

应该计算并输出

5

3

它的用户输入,但只有 2 位数字,它会读取要使用的运算符,然后转到我调​​用该运算符的任何地方,并计算等式。我只是不知道如何循环它所以它也读取下一行。我试着对它进行硬编码,但是使用 div 运算符很难,因为我不关心复杂的数字,所以我清除了上寄存器。

segment .data 

    NO: db 'Invalid input', 10
    nolen: equ $-NO
    
    segment .bss
    ;defining all variables
       space resb 1
       num1 resb 1
       num2 resb 1
       ;second equation
       num3 resb 1
       num4 resb 1
       char resb 1
       char2 resb 1
    ;newline for enter char, maybe
    newlin resb 1
    ;result
       res resb 1   
  
    section .text
       global _start    ;must be declared for using gcc
        
    _start:             ;tell linker entry point
        
     mov cx, 2
     
    ;reading space
       mov eax, 3
       mov ebx, 0  
       mov ecx, space 
       mov edx, 1
       int 0x80  

    ;reading num 1
       mov eax, 3
       mov ebx, 0  
       mov ecx, num1 
       mov edx, 1
       int 0x80  
    
    ;reading space
       mov eax, 3
       mov ebx, 0  
       mov ecx, space 
       mov edx, 1
       int 0x80  

       
    ;reading char
        mov eax, 3
        mov ebx, 0
        mov ecx, char
        mov edx, 1
        int 0x80
            
    ;reading space
       mov eax, 3
       mov ebx, 0  
       mov ecx, space
       mov edx, 1
       int 0x80  


    ;reading num 2
       mov eax, 3
       mov ebx, 0
       mov ecx, num2 
       mov edx, 1
       int 0x80   
                   
    ;reading space
       mov eax, 3
       mov ebx, 0  
       mov ecx, space
       mov edx, 1
       int 0x80  
                          
    ;reading next line
       mov eax, 3
       mov ebx, 0  
       mov ecx, newlin
       mov edx, 1
       int 0x80


    
       ; moving the first number to eax register and second number to ebx
       ; and subtracting ascii '0' to convert it into a decimal number
       ;moving variables in lower halfs
       
       
       mov AX, [char]
       ;compare char to plus sign
       cmp AX, byte '+'
       ;jump to plus function
       je plus
       cmp AX, byte '-'
       ;jump to minus
       je minus
       cmp AX, byte '*'
       ;jump to multiplication
       je multi
       cmp AX, byte '/'
       ;jump to division
       je divi
       jmp Nope
       cmp AX, 2
       je _start

       Nope:
       mov eax, 4
       mov ebx, 1
       mov ecx, NO
       mov edx, nolen
       int 0x80
       jmp exit
       
       plus:
       mov al, [num1]
       mov bl, [num2]
       add al, bl
       sub al, '0'
       mov [res], al
       
       
       ; print the sum 
       mov eax, 4       
       mov ebx, 1
       mov ecx, res        
       mov edx, 1
       cmp ecx, 2
       je _start
       int 0x80
       jmp exit
      
       
       minus:
       mov al, [num1]
       mov bl, [num2]
       sub al, bl
       add al, '0'
       mov [res], al
       ;print the sub 
       mov eax, 4       
       mov ebx, 1
       mov ecx, res         
       mov edx, 1 
       cmp ecx, 2
       je _start
       int 0x80
       jmp exit
       
       multi:
       mov al, [num1]
       mov bl, [num2]
       sub al, '0'
       sub bl, '0'
       ;multiply them
       mul bl
       ;sub bl, '0'
       add al, '0'
       mov [res], al
       ;add al, '0'
       ; print the sum 
       mov eax, 4       
       mov ebx, 1
       mov ecx, res         
       mov edx, 1
       cmp ecx, 2
       je _start
       int 0x80
       jmp exit
       
       divi:
       mov al, [num1]
       mov bl, [num2]
       mov dx, 0
       mov ah, 0
       sub al, '0'
       sub bl, '0'
       div bl
       add ax, '0'
       mov [res], al
       ; print the divide output
       mov eax, 4       
       mov ebx, 1
       mov ecx, res         
       mov edx, 1
       cmp ecx, 2
       je _start
       int 0x80
       jmp exit
      

    exit:    
       mov eax, 1
       mov ebx, 0
       int 0x80

我在看我的教科书,它说要使用 cmp ecx, 2 和 je _start 但我想我没有正确使用它。我至少让它半工作了它只是我无法得到的最后一行。现在它总是正确输出第一个值,只是不打印另一个值。

关于寄存器保存

mov  cx, 2

;reading space
mov  eax, 3
mov  ebx, 0  
mov  ecx, space 
mov  edx, 1
int  0x80

使用 mov cx, 2 指令,您可以设置一个循环计数器,因此您的代码可以 运行 两次。很好,但仅几条指令之后,您就可以使用加载缓冲区地址的 mov ecx, space 指令销毁该计数器。不要忘记 CX 只是 ECX 寄存器的低 16 位。
一种解决方案是将计数器存储在堆栈上。

  mov  ecx, 2        ; Use ECX instead of CX in 32-bit code!
  push ecx           ; (1) Preserving the counter

  ;reading space
  mov  eax, 3
  mov  ebx, 0  
  mov  ecx, space 
  mov  edx, 1
  int  0x80
  ...

这是关于你如何以及在何处环回

举个例子,看plus代码:

; print the sum
mov  eax, 4   
mov  ebx, 1
mov  ecx, res
mov  edx, 1
cmp  ecx, 2     <-- Extra code to loop back 
je   _start     <--
int  0x80
jmp  exit

首先,你应该把额外的代码放在 int 0x80 指令下面,这样打印函数就可以先完成它的工作。
其次,ECX 寄存器不包含您的循环计数器,因为 mov ecx, res 指令就在上面几行!
第三,使用计数器意味着代码需要操纵它。大多数情况下,这归结为递减它。

快速解决方案:

  ; print the sum 
  mov  eax, 4       
  mov  ebx, 1
  mov  ecx, res        
  mov  edx, 1
  int  0x80

  pop  ecx           ; (1) Restoring the counter
  dec  ecx           ; Decrementing the counter
  jnz  _start        ; Looping back if the counter is not yet zero
  jmp  exit          ; Exit program if the counter has become zero

现在您可以将此应用于 4 个代码块中的每一个 plusminusmulti,和 divi,或者你可以写得更聪明一些:

plus:
  ...                ; Calculating and printing go here
  jmp  MORE
minus:
  ...                ; Calculating and printing go here
  jmp  MORE
multi:
  ...                ; Calculating and printing go here
  jmp  MORE
divi:
  ...                ; Calculating and printing go here
  jmp  MORE

MORE:
  pop  ecx           ; (1) Restoring the counter
  dec  ecx           ; Decrementing the counter
  jnz  _start        ; Looping back if the counter is not yet zero
exit:                ; Exit program if the counter has become zero
  mov  eax, 1
  mov  ebx, 0
  int  0x80

这是关于你循环回到的地方

_start 标签是程序开始执行的地方。这不能成为循环返回的目标,因为如果我们这样做,我们将永远重新初始化计数器并且程序永远不会终止。
我们保留计数器的行是循环返回的正确目标:

  mov  ecx, 2        ; Use ECX instead of CX in 32-bit code!
AGAIN: <----------------------------------------------------------------\
  push ecx           ; (1) Preserving the counter                        |
                                                                         |
  ...                                                                    |
                                                                         |
MORE:                                                                    |
  pop  ecx           ; (1) Restoring the counter                         |
  dec  ecx           ; Decrementing the counter                          |
  jnz  AGAIN         ; Looping back if the counter is not yet zero -----/
exit:                ; Exit program if the counter has become zero
  mov  eax, 1
  mov  ebx, 0
  int  0x80

需要持续关注的事情

mov  AX, [char]
;compare char to plus sign
cmp  AX, byte '+'
;jump to plus function
je   plus

char 变量是一个 byte。永远不要把它当作一个词来读。如果讨厌的事情会发生,它们就会发生...

  mov  al, [char]
  cmp  al, '+'
  je   plus
  cmp  al, '-'
  je   minus
  cmp  al, '*'
  je   multi
  cmp  al, '/'
  je   divi
Nope:
  mov  eax, 4
  mov  ebx, 1
  mov  ecx, NO
  mov  edx, nolen
  int  0x80
  jmp  exit

最后要说一句

jmp Nope
cmp AX, 2           <- These lines will NEVER execute
je _start           <-
Nope: