实验目标
How many integers will be added? 21
The array cannot be larger than 20
精心设计程序,使得在修改了ARRAY_SIZE后,错误提示信息中的ARRAY_SIZE数目值(在上例中是20)也应自动修改。
提示:
a). 编程能力一般的同学可以分两步:①弄懂附录A的程序。该程序实现了3个整个求和的功能。 ②找到附录A的程序需要修改的地方,以实现多个整数求和。
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
str0 BYTE "How many integers will be added? ",0
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
str3 BYTE "The array cannot be larger than 20",0
ARRAY_SIZE = 20
Array DWORD ARRAY_SIZE DUP(?)
.code
main PROC
call Clrscr
mov esi,OFFSET Array
call CountNum
call PromptForIntegers
call ArraySum
Call DisplaySum
exit
main ENDP
CountNum PROC
mov edx,OFFSET str0
call WriteString
call ReadInt
call Crlf
mov ecx, eax
ret
CountNum 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 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
TITLE Integer Summation Program (Sum2.asm)
INCLUDE Irvine32.inc
;INTEGER_COUNT = 3
.data
str0 BYTE "How many integers will be added? ",0
str1 BYTE "Enter a signed integer: ",0
str2 BYTE "The sum of the integers is ",0
str3 BYTE "The array cannot be larger than 20",0
str4 BYTE "The negative sum of the integers is ",0
ARRAY_SIZE = 20
Array DWORD ARRAY_SIZE DUP(?)
.code
main PROC
call Clrscr
mov esi,OFFSET Array
call CountNum
call PromptForIntegers
call ArraySum
Call DisplaySum
exit
main ENDP
CountNum PROC
mov edx,OFFSET str0
call WriteString
call ReadInt
call Crlf
mov ecx, eax
ret
CountNum ENDP
PromptForIntegers PROC USES ecx edx esi
mov edx,OFFSET str1
L1: call WriteString
call ReadInt
call Crlf
cmp eax, 20 ;比较是否超过20
ja too_big_error
;处理小于等于20的代码
Small: mov [esi],eax
add esi,TYPE DWORD
loop L1
ret
; 注意:顺序执行时会执行下面处理错误情况的代码,可以使用jmp指令绕开
too_big_error:
; 处理大于20的错误情况的代码
;call DumpRegs ; display registers
cmp eax,0
jl Small
call DisplayError
exit
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 str4
mov eax,ebx
call writestring
call writeint
call Crlf
ret
DisplaySum ENDP
DisplayError PROC USES edx
mov edx,OFFSET str3
call WriteString
call Crlf
ret
DisplayError ENDP
END main
结语
打完收工~