1. 程式人生 > >VC6彙編第二次上機實驗

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 arrayarray的偏移量移到esi暫存器中。OFFSET的作用就是計算當前變數在段中起始的偏移量,那麼就是str1str2的長度。

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 過程指明需要用到ECXEDXESI暫存器。 WriteStringwrite null-terminated string to output,指把字串輸出。ReadIntread signed decimal integer from console,指從控制檯上讀取數字。WriteStringReadInt均為Irvine32庫函式。

mov [esi],eax是把EAX暫存器的值送到ESI記憶體裡面,從鍵盤裡面輸入的值會在EAX裡面。

add esi,TYPE DWORDESI暫存器加一個雙字的偏移量,因為數字是一個雙字,代表進棧。

LoopECX之間進行比較,如果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暫存器中。然後輸出的時候,我分別輸出EAXEBX的累加總和,那不就是正數的總和和負數的總和了嘛~~~~

注意:

  • 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

這裡寫圖片描述

##結語 打完收工~