汇编语言-实验(二)

实验目的

  1. 掌握程序设计中的3种基本结构(顺序结构、选择程序、循环程序)。
  2. 熟练使用汇编语言的指令:数据传送类指令、数据运算类指令、逻辑判断类指令与转移指令、循环指令等。
  3. 初步了解系统功能调用的使用方法,尝试使用01H号功能调用进行字符输入的方法及使用02H号功能调用进行字符输出(显示)的方法。

程序说明

  1. 计算1+2+3+…+10,将结果显示在屏幕上。
  2. 利用01H号功能调用输入10个一位数字,并将其由ASCII码转换为二进制数,依此保存到变量BUF的10个字节中,变量BUF的形式为BUF DB 10 DUP(?)。编程求出这10个数中的最大数和最小数,将最大数存入MAX单元、最小数存入MIN单元,并将其在屏幕上显示出来。

设计思想

题目一

如下图所示,首先通过循环求出1+2+…+10,然后调用子程序display显示sum

sum.png

题目二

如下图所示,首先调用子程序getinput获取用户输入,同时存储进数组,并更新maxmin,最后调用两次子程序display显示maxmin

maxmin.png

程序代码

题目一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
;*********************************************************************

data segment ; 定义数据段
sum dw 0 ; 存储和
data ends

;*********************************************************************

code segment ; 定义代码段
assume cs:code,ds:data

;---------------------------------------------------------------------

main proc far ; 程序的主部分
start:
; 为返回DOS做准备
push ds ; ds压栈
xor ax,ax ; (ax) <- 0
push ax ; ax压栈

; ds设为data
mov ax,data ; (ax) <- data
mov ds,ax ; (ds) <- (ax)

mov cx,10 ; 从10加到1

next:
add sum,cx ; sum <- sum+(cx)
loop next ; (cx) <- (cx)-1

mov ax,sum ; (ax) <- sum
call display ; 调用子程序以十进制显示(ax)

; 返回DOS环境
ret ; 返回DOS环境
main endp

;---------------------------------------------------------------------

display proc near ; 将(ax)以十进制形式输出

; 保存寄存器
push ax
push bx
push cx
push dx
push si

; 初始化
mov si,0 ; 数字的位数
mov bl,10 ; 数字之后除以bx,即10


; 数字每位倒序压栈
prepare:
div bl ; 被除数默认为(ax),除以10。
add ah,30h ; (ah)为默认的余数寄存器,转换为ASCII码,字符0的ASCII码为48,即30h
push ax ; 存储最后一位
and ax,00ffh; (ah)<-0
mov cx,ax ; al为默认的商寄存器。ax=ah+al。当商为0时则跳出循环
inc si ; 更新数字位数
inc cx ; 如果为0,加一之后为1。loop判断前会将cx减一。
loop prepare;

; 弹栈,并用十进制显示
mov cx,si ; si为数字位数,即循环运行次数
show:
pop ax ; 获取要显示的数据
mov dl,ah ; 要显示的数据放在dl里
mov ah,2 ; 2号功能
int 21h ; 调用DOS
loop show

; 恢复寄存器
pop si
pop dx
pop cx
pop bx
pop ax

; 返回
ret

display endp ; display子程序结束

code ends
;*********************************************************************
end start

题目二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
;*********************************************************************

data segment ; 定义数据段
buf db 10 dup(-1) ; 存储10个输进来的数字
max db 0 ; 最大值,输入的数字一定大于等于0
min db 9 ; 最小值,输入的数字一定小于等于9
data ends

;*********************************************************************

code segment ; 定义代码段
assume cs:code,ds:data

;---------------------------------------------------------------------

main proc far ; 程序的主部分
start:
; 为返回DOS做准备
push ds ; ds压栈
xor ax,ax ; (ax) <- 0
push ax ; ax压栈

; ds设为data
mov ax,data ; (ax) <- data
mov ds,ax ; (ds) <- (ax)

; 获取用户输入并进行存储,记录最大值最小值


call getinput ; 数字存入al,显示一下

; 显示最大值
mov al,max ; 显示最大值
and ax,00ffh ; (ah)<-0
call display ; 调用子程序以十进制显示(ax)

; 显示最小值
mov al,min ; 显示最小值
and ax,00ffh ; (ah)<-0
call display ; 调用子程序

; 返回DOS环境
ret ; 返回DOS环境
main endp

;---------------------------------------------------------------------

getinput proc near ; 获取用户输入并进行存储,记录最大值最小值
; 保存寄存器
push ax
push bx
push cx

; 初始化
mov cx,10 ; 10个输入
lea bx,buf ; 存储数组地址,用来遍历数组

; 获取用户输入
savetoarray:
mov ah,1 ; 1号功能,获取用户输入,保存至al
int 21h ; 调用DOS

; 存入数组
sub al,30h ; (al)减去30h由ASCII码转为十进制数,在计算机内自动用二进制表示
mov [bx],al ; 存入数组,相对寻址方式
inc bx ; 数组地址加一

; 判断是否更新最大值
updatemax:
cmp al,max ; (ax)<-max
jl updatemin ; (ax)<max,则不用更新
mov max,al ; 更新最大值

; 判断是否更新最小值
updatemin:
cmp al,min ; (ax)<-min
jg loopp ; (ax)>min,则不用更新
mov min,al ; 更新最小值

; 循环savetoarray
loopp:
loop savetoarray ; cx减一,循环至cx为0

; 恢复寄存器
pop cx
pop bx
pop ax

; 返回
ret

getinput endp ; getinput子程序结束

;---------------------------------------------------------------------

display proc near ; 将(ax)以十进制形式输出

; 保存寄存器
push ax
push bx
push cx
push dx
push si

; 初始化
mov si,0 ; 数字的位数
mov bl,10 ; 数字之后除以bx,即10


; 数字每位倒序压栈
prepare:
div bl ; 被除数默认为(ax),除以10。
add ah,30h ; (ah)为默认的余数寄存器,转换为ASCII码,字符0的ASCII码为48,即30h
push ax ; 存储最后一位
and ax,00ffh; (ah)<-0
mov cx,ax ; al为默认的商寄存器。ax=ah+al。当商为0时则跳出循环
inc si ; 更新数字位数
inc cx ; 如果为0,加一之后为1。loop判断前会将cx减一。
loop prepare;

; 弹栈,并用十进制显示
mov cx,si ; si为数字位数,即循环运行次数
show:
pop ax ; 获取要显示的数据
mov dl,ah ; 要显示的数据放在dl里
mov ah,2 ; 2号功能
int 21h ; 调用DOS
loop show

; 恢复寄存器
pop si
pop dx
pop cx
pop bx
pop ax

; 返回
ret

display endp ; display子程序结束
code ends
;*********************************************************************
end start

问题回答

设计的程序包含了几个段

题目一和题目二的程序各设计了两个段:数据段和代码段。

你的代码经过编译和链接之后,总共占用多少个字节

题目一和题目二程序编译链接后大小均为1KB。

调用DEBUG进行反汇编,查看程序的第一条指令的地址码是多少?最后一条指令的地址码是多少?

  1. 题目一第一条指令的地址码为076B:0000,最后一条指令的地址码为076B:0018。因为使用了一个子程序,所以主程序较短。
  2. 题目二第一条指令的地址码为076B:0000,最后一条指令的地址码为076B:001E。因为使用了两个子程序,所以主程序较短。

对于第2题,怎样修改程序可以同时实现将10个数字的累加功能

  1. 首先在数据段中定义变量,代码如:sum db 0
  2. 然后在getinput子程序中savetoarraysub al,30h后添加代码add sum,al

对于第2题,若要求输入的是两位数,又该怎么办?

  1. 首先(cx)改为20;
  2. 然后每两个数字一组:其中先得到的数字转换为十进制数字A暂存,后得到的数字转换成十进制数字B暂存;
  3. 可知我们要操作的数字为A*10+B(可以通过乘法和加法实现);
  4. 其他程序不变。

结果分析

题目一

运行程序,可见输出了1+2+…+10=55。

题目二

运行程序,输入9876543210共10个数字,可见输出了最大值9和最小值0。

查看数据段dds:0,结果如下,可知数字均已存入buf数组。

作者:@臭咸鱼

转载请注明出处:https://chouxianyu.github.io

欢迎讨论和交流!