首页 > 解决方案 > 循环到第二个方程

问题描述

我正在用 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 但我想我没有正确使用它。我至少让它半工作它只是我无法得到的最后一行。现在它总是正确地输出第一个值,只打印另一个值。

标签: assemblynasm

解决方案


这是关于寄存器保存

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

这是关于你如何以及在哪里循环回来

例如,看一下加号代码:

; 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 个代码块plusminusmultidivi中的每一个,或者您可以更智能地编写它:

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:

推荐阅读