assembly - 循环到第二个方程
问题描述
我正在用 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
...
这是关于你如何以及在哪里循环回来
例如,看一下加号代码:
; 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 个代码块plus、minus、multi和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:
推荐阅读
- verilog - 在 Verilog 中,“for 循环”可以是可变大小的吗?
- jquery - 隐藏按钮后显示按钮的问题
- elasticsearch - ElasticSearch must-terms 不返回数据
- bootstrap-4 - aria-expanded="false" 在引导模板中不起作用
- node.js - 电子打开多个窗口 package.json 调整
- excel - 如何在excel中使用嵌套评估函数
- c - 函数的参数怎么可能是类型?(类似于 va_arg 的第二个参数)
- android - 试图访问内部类中的 FOR 循环变量,这是一个范围问题
- arrays - 比较两个切片的缺失元素
- python - 如何修复python递归函数