VC6彙編第二次上機實驗
####實驗目標
- A、編寫多個整數求和的程式: 對使用者輸入的多個整數進行求和,並輸出結果。 閱讀然後修改附錄A中的求和程式(該程式實現了3個整個求和的功能),使用一個常量決定陣列的大小(即程式最大可以求和的整數個數): ARRAY_SIZE = 20 Array DWORD ARRAY_SIZE DUP(?) 寫一個過程提示使用者輸入需要求和的整數的個數,向promptForIntegers過程傳遞使用者輸入的數值。如果使用者的輸入值大於ARRAY_SIZE(判斷的示例程式碼參見附錄B),那麼顯示一條錯誤資訊並退出程式。提示和錯誤資訊可以如下例所示:
How many integers will be added? 21 The array cannot be larger than 20
精心設計程式,使得在修改了ARRAY_SIZE後,錯誤提示資訊中的ARRAY_SIZE數目值(在上例中是20)也應自動修改。 提示: a). 程式設計能力一般的同學可以分兩步:①弄懂附錄A的程式。該程式實現了3個整個求和的功能。 ②找到附錄A的程式需要修改的地方,以實現多個整數求和。 b). 程式設計能力較強的同學建議直接編寫程式實現。
- B、對上述程式新增功能:除顯示多個整數的和外,還分別顯示這些整數中正整數的和負整數的和。(區分正數與負數的示例程式碼參見附錄B)
####實驗附錄
- 附錄A 程式功能:由使用者輸入3個整個數,然後對這3個整數進行求和,並輸出結果。
- 附錄B
1.比較無符號數是否超過20的示例程式碼:
cmp var_A, 20 ; var_A可以為記憶體運算元,也可以為暫存器
ja too_big_error
; 處理小於等於20的程式碼
; …
; 注意:順序執行時會執行下面處理錯誤情況的程式碼,可以使用jmp指令繞開
too_big_error:
; 處理大於20的錯誤情況的程式碼
2.判斷有符號數是正數還是負數的示例程式碼:
cmp var_A, 0 ; var_A可以為記憶體運算元,也可以為暫存器 jge positive_and_0 ; 處理負數的程式碼 ; … ; 注意:順序執行時會執行下面處理正數和0的程式碼,可以使用jmp指令繞開 positive_and_0: ; 處理正數和0的程式碼
####程式原始碼
TITLE Integer Summation Program (Sum2.asm)
INCLUDE Irvine32.inc
INTEGER_COUNT = 3
.data
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
array DWORD INTEGER_COUNT DUP(?)
.code
main PROC
call Clrscr
mov esi,OFFSET array
mov ecx,INTEGER_COUNT
;call DumpRegs ; display registers
call PromptForIntegers
call ArraySum
Call DisplaySum
exit
main ENDP
PromptForIntegers PROC USES ecx edx esi
mov edx,OFFSET str1
L1: call WriteString
call ReadInt
call Crlf
mov [esi],eax
add esi,TYPE DWORD
call DumpRegs ; display registers
loop L1
ret
PromptForIntegers ENDP
ArraySum PROC USES esi ecx
mov eax,0
L1:add eax,[esi]
add esi,TYPE DWORD
loop L1
ret
ArraySum ENDP
DisplaySum PROC USES edx
mov edx,OFFSET str2
call WriteString
call WriteInt
call Crlf
ret
DisplaySum ENDP
END main
####程式原始碼過程簡單分析 既然實驗需要我們修改程式,那麼我們肯定需要先清楚源程式的大致執行過程,這樣我們才能更好地弄懂程式、修改程式。
1. .data定義部分
INCLUDE Irvine32.inc
INTEGER_COUNT = 3
.data
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
array DWORD INTEGER_COUNT DUP(?)
學過C語言都知道,就是類似於C語言的一些簡單宣告而已。 其中array定義為雙字,3個佔位符。
2.main函式過程
main PROC
call Clrscr
mov esi,OFFSET array
mov ecx,INTEGER_COUNT
;call DumpRegs ; display registers
call PromptForIntegers
call ArraySum
Call DisplaySum
exit
main ENDP
Clrscr
是一Irvine32
庫的一個函式,函式作用為clear the screen
也就是清屏意思。
mov esi,OFFSET array
把array
的偏移量移到esi
暫存器中。OFFSET
的作用就是計算當前變數在段中起始的偏移量,那麼就是str1
和str2
的長度。
mov ecx,INTEGER_COUNT
,因為INTEGER_COUNT
是3,所以ECX
暫存器的值為3。這裡特別強調一下,因為Loop
指令是和ECX
的值有關的。當Loop
迴圈一次,ECX
的值減少一次。當ECX
不為0時候,會繼續執行Loop
對應的目標命令,如果ECX
為0,那麼就不再執行Loop
目標命令,而是用RET
命令返回到過程入口。
call DumpRegs
是呼叫Irvine32
庫的函式,作用是打印出各個暫存器的值和標誌位的狀態。
call PromptForIntegers
call ArraySum
Call DisplaySum
分別是呼叫`PromptForIntegers`、`ArraySum`、`DisplaySum`的過程。
3.PromptForIntegers 過程
PromptForIntegers PROC USES ecx edx esi
mov edx,OFFSET str1
L1: call WriteString
call ReadInt
call Crlf
mov [esi],eax
add esi,TYPE DWORD
call DumpRegs ; display registers
loop L1
ret
PromptForIntegers ENDP
PromptForIntegers
過程指明需要用到ECX
、EDX
、ESI
暫存器。
WriteString
是 write null-terminated string to output
,指把字串輸出。ReadInt
是 read signed decimal integer from console
,指從控制檯上讀取數字。WriteString
、ReadInt
均為Irvine32
庫函式。
mov [esi],eax
是把EAX暫存器的值送到ESI
記憶體裡面,從鍵盤裡面輸入的值會在EAX
裡面。
add esi,TYPE DWORD
讓ESI
暫存器加一個雙字的偏移量,因為數字是一個雙字,代表進棧。
Loop
和ECX
之間進行比較,如果ECX
為0,則跳出該過程。
4.ArraySum 過程
ArraySum PROC USES esi ecx
mov eax,0
L1:add eax,[esi]
add esi,TYPE DWORD
loop L1
ret
ArraySum ENDP
根據上面的分析,ArraySum
過程就是把ESI
暫存器記憶體的值取出來然後累加。
4.DisplaySum 過程
DisplaySum PROC USES edx
mov edx,OFFSET str2
call WriteString
call WriteInt
call Crlf
ret
DisplaySum ENDP
DisplaySum
過程就是把str2
字串的內容和累加的和顯示在控制檯上。
##完成實驗目標 ######目標A 目標A的意思就是當輸入的值大於20時候,就提示不能大於20並且結束程式,輸入值小於20時候就正常執行累加。
經過上面的分析,那麼就應該在輸入過程PromptForIntegers
中進行修改程式即可,加一個判斷是否大於20的條件即可。
######修改過後的程式碼:
TITLE Integer Summation Program (Sum2.asm)
INCLUDE Irvine32.inc
INTEGER_COUNT = 3
.data
;str1 BYTE "Enter a signed integer: ",0
str1 BYTE "How many integers will be added? ",0
str2 BYTE "The sum of the integers is ",0
str3 BYTE "The array cannot be larger than 20",0
array DWORD INTEGER_COUNT DUP(?)
ARRAY_SIZE = 20
Array1 DWORD ARRAY_SIZE DUP(?)
.code
main PROC
call Clrscr
mov esi,OFFSET array
mov ecx,INTEGER_COUNT
;call DumpRegs ; display registers
call PromptForIntegers
call ArraySum
Call DisplaySum
exit
main ENDP
PromptForIntegers PROC USES ecx edx esi
mov edx,OFFSET str1
L1: call WriteString
call ReadInt
call Crlf
cmp eax, ARRAY_SIZE ;比較是否超過20
ja too_big_error
;處理小於等於20的程式碼
mov [esi],eax
add esi,TYPE DWORD
call DumpRegs ; display registers
loop L1
ret
; 注意:順序執行時會執行下面處理錯誤情況的程式碼,可以使用jmp指令繞開
too_big_error:
; 處理大於20的錯誤情況的程式碼
call DisplayError
exit
PromptForIntegers ENDP
ArraySum PROC USES esi ecx
mov eax,0
L1:add eax,[esi]
add esi,TYPE DWORD
loop L1
ret
ArraySum ENDP
DisplaySum PROC USES edx
mov edx,OFFSET str2
call WriteString
call WriteInt
call Crlf
ret
DisplaySum ENDP
DisplayError PROC USES edx
mov edx,OFFSET str3
call WriteString
;call WriteInt
call Crlf
ret
DisplayError ENDP
END main
######目標B 目標B是讓我們分別把輸入的正數求一個和,輸入的負數求一個和。
既然知道問題了,那麼這個就很簡單了,加入我一次性輸入4個數,比如是:1,-1,2,-2。那麼我從[ESI]
中取出數的時候,和0比較一下,大於0的就是正數,然後我累加到EAX
暫存器中。小於0的就是負數,然後我就累加到EBX
暫存器中。然後輸出的時候,我分別輸出EAX
、EBX
的累加總和,那不就是正數的總和和負數的總和了嘛~~~~
注意:
CMP
指令後面目的運算元和源運算元,可以一個是暫存器、一個是數字,但不能兩個都是數字。[ESI]
這個取出來就是一個數字,所以後面就要藉助EDX
(EDX
存的是0)來比較。- 記得要初始化使用到的暫存器
######修改過後的程式碼:
TITLE Integer Summation Program (Sum2.asm)
INCLUDE Irvine32.inc
INTEGER_COUNT = 4
.data
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The positive sum of the integers is ",0
str3 BYTE "The negative sum of the integers is ",0
array DWORD INTEGER_COUNT DUP(?)
ARRAY_SIZE = 20
Array1 DWORD ARRAY_SIZE DUP(?)
.code
main PROC
call Clrscr
mov esi,OFFSET array
mov ecx,INTEGER_COUNT
call PromptForIntegers
call ArraySum
Call DisplaySum
exit
main ENDP
PromptForIntegers PROC USES ecx edx esi ebx
mov edx,OFFSET str1
L1: call WriteString
call ReadInt
call Crlf
mov [esi],eax
add esi,TYPE DWORD
loop L1
ret
PromptForIntegers ENDP
ArraySum PROC USES esi ecx
mov eax,0
mov ebx,0
mov edx,0
L1: cmp[esi],edx
jl Feng1
add eax,[esi]
jmp Feng2
Feng1:add ebx,[esi]
Feng2:add esi,TYPE DWORD
loop L1
ret
ArraySum ENDP
DisplaySum PROC USES edx
mov edx,OFFSET str2
call WriteString
call WriteInt
call Crlf
mov edx,OFFSET str3
mov eax,ebx
call writestring
call writeint
call Crlf
ret
DisplaySum ENDP
END main
##結語 打完收工~