循环到第二个方程
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 个代码块中的每一个 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:
我正在制作一个 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 个代码块中的每一个 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: