我正在用nasm 86x制作一個小計算器,它可以讀取兩行形式的方程式
。3 2
6 / 2
它應該計算并輸出
5
3
它是用戶輸入的,但只有2個數字,它將讀取要使用的運算子,然后轉到我呼叫該運算子的地方,并做方程。我只是不知道如何回圈,以便它也能讀到下一行。我試著用硬編碼,但對于div運算子來說很困難,因為我清除了上面的暫存器,因為我不關心復雜的數字。
segment .data
NO: db 'Invalid input', 10
nolen: equ $-NO
段 .bss
;定義所有的變數
space resb 1
num1 resb 1
num2 resb 1
;第二個方程
num3 resb 1
num4 resb 1
char resb 1
char2 resb 1
;換行用于輸入字符,也許
newlin resb 1
;結果
resb 1
.text部分
全域_start ;使用gcc時必須宣告。
_start: ;告訴聯結器入口點
mov cx, 2
;讀取空間
mov eax, 3
mov ebx, 0
mov ecx, space
mov edx, 1
int 0x80
;讀取數字1
mov eax, 3
mov ebx, 0
mov ecx, num1
mov edx, 1
int 0x80
;讀取空間
mov eax, 3
mov ebx, 0
mov ecx, space
mov edx, 1
int 0x80
;讀取字符
mov eax, 3
mov ebx, 0
mov ecx, char
mov edx, 1
int 0x80
;讀取空間
mov eax, 3
mov ebx, 0
mov ecx, space
mov edx, 1
int 0x80
;讀取數字2
mov eax, 3
mov ebx, 0
mov ecx, num2
mov edx, 1
int 0x80
;讀取空間
mov eax, 3
mov ebx, 0
mov ecx, space
mov edx, 1
int 0x80
;讀取下一行
mov eax, 3
mov ebx, 0
mov ecx, newlin
mov edx, 1
int 0x80
; 將第一個數字移至eax暫存器,第二個數字移至ebx暫存器
并減去ascii'0',將其轉換為十進制數字
;移動下半部分的變數
mov AX, [char].
;比較char和正號
cmp AX, 位元組 '
;跳轉到加號函式
跳轉到加號
cmp AX, byte '-' ;跳到減號函式
;跳轉到減號
跳轉到減法函式 je minus
cmp AX, 位元組 '*
;跳轉到乘法
je multi
cmp AX, 位元組 '/'
跳轉到除法
je divi
jmp Nope
cmp AX, 2
je _start
不對。
mov eax, 4
mov ebx, 1
mov ecx, NO
mov edx, nolen
int 0x80
jmp exit
加。
mov al, [num1].
mov bl, [num2]
添加al, bl
子al,'0
mov [res], al
列印總和
mov eax, 4
mov ebx, 1
mov ecx, res
mov edx, 1
cmp ecx, 2
je _start
int 0x80
jmp exit
減去。
mov al, [num1].
mov bl, [num2]
sub al, bl
添加al,'0
mov [res], al
;列印子程式
mov eax, 4
mov ebx, 1
mov ecx, res
mov edx, 1
cmp ecx, 2
je _start
int 0x80
jmp exit
多。
mov al, [num1].
mov bl, [num2]
子al,'0'
sub bl, '0
;將它們相乘
mul bl
;sub bl, '0'
添加al,'0
mov [res], al
;添加al,'0
;列印總和
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
子al,'0
sub bl, '0
div bl
添加ax,'0
mov [res], al
; 列印除法的輸出
mov eax, 4
mov ebx, 1
mov ecx, res
mov edx, 1
cmp ecx, 2
je _start
int 0x80
jmp exit
退出。
mov eax, 1
mov ebx, 0
int 0x80
我讀了我的教科書,它說要使用cmp ecx, 2和je _start,但我想我沒有正確使用它。我至少讓它達到了半作業狀態,只是最后一行我無法做到。現在,它總是正確地輸出第一個值,只是對其他的值沒有列印出來。
uj5u.com熱心網友回復:
這是關于暫存器的保存
。mov cx, 2 ;讀取空間 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 ; 在32位代碼中使用ECX而不是CX!
push ecx ; (1) 保留計數器
;讀取空間
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 <-- 額外的代碼來回回圈
je _start <--
int 0x80
jmp exit
首先,你應該將額外的代碼放在int 0x80指令的下面,這樣列印函式就可以先完成它的作業。
第二,ECX暫存器不包含你的回圈計數器,因為mov ecx, res指令就在上面的幾行!
。
第三,使用計數器意味著代碼需要對其進行操作。大多數情況下,這可以歸結為對它進行遞減。
一個快速的解決方案:
; 列印總和
mov eax, 4
mov ebx, 1
mov ecx, res
mov edx, 1
int 0x80
pop ecx ; (1) 恢復計數器
dec ecx ; 遞減計數器
jnz _start ; 如果計數器還沒有歸零,則回圈往復。
jmp exit ; 如果計數器為零則退出程式
現在你可以將此應用于4個代碼塊plus、minus、multi和divi中的每一個,或者你可以寫得更聰明些:
plus。
... ; 計算和列印在這里進行
jmp MORE
減去。
... ; 計算和列印在這里進行
jmp MORE
多。
... ; 計算和列印在這里進行
jmp MORE
divi:
... ; 計算和列印到此為止
jmp MORE
MORE:
pop ecx ; (1) 恢復計數器
dec ecx ; 遞減計數器
jnz _start ; 如果計數器還沒有歸零,則回環計算
exit: ; 如果計數器為零則退出程式
mov eax, 1
mov ebx, 0
int 0x80
這是關于你回環到哪里的問題
_start標簽是程式開始執行的地方。這不能成為回環的目標,因為如果我們這樣做,我們將永遠重新初始化計數器,程式將永遠無法終止。 我們保留計數器的那一行才是正確的回環目標:char變數是一個byte。千萬不要把它當作一個字來讀。如果討厭的事情會發生,它們就會發生......
標籤: 上一篇:BT指令與進位標志CF之間的聯系
下一篇:堆疊是如何區分不同的數字型別的?
mov ecx
mov ecx, 2 ; 在32位代碼中使用ECX而不是CX!
AGAIN: <----------------------------------------------------------------
push ecx ; (1)保留計數器。
|
... |
|
更多 |
pop ecx ; (1) 恢復計數器|
dec ecx ; 遞減計數器。
jnz AGAIN ; 如果計數器還沒有歸零,則回圈往復 -----/
exit: ; 如果計數器為零則退出程式
mov eax, 1
mov ebx, 0
int 0x80
需要繼續注意的事項
mov AX, [char].
;比較char和plus符號
cmp AX, byte '
;跳轉到加號函式
跳轉到加號
mov al, [char].
cmp al, ' '
je plus
cmp al, '-'
je minus
cmp al, '*
多重
cmp al, '/'。
讀取Divi
諾普。
mov eax, 4
mov ebx, 1
mov ecx, NO
mov edx, nolen
int 0x80
jmp退出
一定要有一個最后的評論
。
jmp Nope
cmp AX, 2 <- 這些行將永遠不會執行
je _start <-
Nope。
