汇编语言实验
本学期汇编课程已经结束,整理一下曾经做过的题目和写过的汇编代码。
使用dosbox环境masm5.0编译器,debug方式可以看我这篇文章https://blog.csdn.net/qq_41420747/article/details/89419241
-
实验题
循环程序设计
1. 有一个首地址为Arr的N字数组,编程求数组中的最大值和最小值,并存入MAX和MIN地址单元中。
Data segment
Arr dw 1H,3H,2H
N EQU 3 ; 这里可以 $-Arr / 2 因为dw 是双字节
Max dw ?
Min dw ?
Data ends
Code segment
Assume cs:Code, ds:Data
Start:
mov ax,Data
mov ds,ax
mov dx,Arr
mov ax,Arr
mov si,00H
mov cx,N-1
NEXT:
add si,2
cmp dx,Arr[si]
jle jmp1
mov dx,Arr[si]
jmp1: ; do nothing
cmp ax,Arr[si]
jge jmp2
mov ax,Arr[si]
jmp2: ; do nothing
LOOP NEXT
mov Max,dx
mov Min,ax
MOV AH,4CH ;返回dos
INT 21H
Code ends
end Start
调试结果:
2. 显示一个十六进制数(XXXXH)
思路:循环位移4位后,每次取出bx(存放16进制数)的低第四位,加上‘0’判断是否在0-9ascii码范围内在则直接打印不在则加7再打印,重复4次。最后打印一个’H’。测试数:1E2AH存入BX
Code segment
assume cs:Code
start:
mov ax,Code
mov ds,ax
xor ax,ax; to 0
xor cx,cx; to 0
xor bx,bx; to 0
mov bx,1E2AH
mov ch,4
rotate:
mov cl,4
rol bx,cl
mov al,bl
and al,0FH
add al,30H
cmp al,3aH
jl print
add al,7H
print:
mov dl,al
mov ah,2
int 21H
dec ch
jnz rotate
mov dl,'H'
mov ah,2
int 21H
mov ah,4cH
int 21H
Code ends
end start
运行结果:
3. 编制一个程序把BX寄存器内的二进制数用十进制的形式在屏幕上显示出来。
思路: 将bx中的内容mov到ax,分别除10000,1000,100,10,将商放到data segment存起来,将余数放回ax继续除,直到余数为一位数,再将data segment的数顺序打印出来。
Datas segment
decnum db 5 dup(?)
Datas ends
Code segment
assume cs:Code,ds:Datas
start:
mov ax,Datas
mov ds,ax
mov bx,0FFFFH ; 要转换的数
lea si,decnum
mov dx,0 ;dx一定要置零
mov ax,bx
mov cx,10000
div cx
mov [si],al
inc si
mov ax,dx;把上一次运算的余数放入ax
mov dx,0
mov cx,1000
div cx
mov [si],al
inc si
mov ax,dx
mov dx,0
mov cx,100
div cx
mov [si],al
inc si
mov ax,dx
mov dx,0
mov cx,10
div cx
mov [si],al
inc si
mov [si],dl
;****循环打印data段数据 decnum****
lea si,decnum
mov cx,5
next:
mov dx,[si]
add dx,'0'
mov ah,2
int 21H
inc si
loop next
mov ah,4cH
int 21H
Code ends
end start
运行结果:
调试
分支程序设计
1. 设有10个学生的成绩分别是76,69,84,90,73,88,99,63,100和80分。试编制一个程序统计60~69分,70~79分,80~89分,90~99分和100分的人数,分别存放到S6,S7,S8,S9和S10单元中。
Datas segment
STU db 76,69,84,90,73,88,99,63,100,80
S6 db 0
S7 db 0
S8 db 0
S9 db 0
S10 db 0
Datas ends
Code segment
assume ds:Datas,cs:Code
start:
mov ax,Datas
mov ds,ax
xor ax,ax
mov si,0
mov cx,10
next:
mov al,byte ptr [si]
cmp ax,69
jg jmp1
add S6,1
jmp final
jmp1:
cmp ax,79
jg jmp2
add S7,1
jmp final
jmp2:
cmp ax,89
jg jmp3
add S8,1
jmp final
jmp3:
cmp ax,99
jg jmp4
add S9,1
jmp final
jmp4:
add S10,1
final:
inc si
loop next
mov dl,S6
mov ah,2H
int 21H
mov dl,S7
mov ah,2H
int 21H
mov dl,S8
mov ah,2H
int 21H
mov dl,S9
mov ah,2H
int 21H
mov dl,S10
mov ah,2H
int 21H
mov ah,4cH
int 21H
Code ends
end start
运行结果:
2. 试编写一个汇编语言程序,要求对键盘输入的小写字母用大写字母显示出来。
Data segment
max_len db 100
real_len db ?
str1 db 100 dup('$')
Data ends
Code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
lea dx,max_len
mov ah,0AH
int 21H
mov dl,0DH
mov ah,02H
int 21H
mov dl,0AH
mov ah,02H
int 21H
; 字符大小写转换
xor cx,cx
mov cl,real_len
mov si,0
lop:
mov bl,str1[si]
cmp bl,61H
jb ok
cmp bl,7AH
ja ok
sub bl,20H
mov str1[si],bl
ok:
inc si
loop lop
lea dx,str1
mov ah,09H
int 21H
mov ah,4cH
int 21H
Code ends
end start
运行结果:
3. 以T为首地址定义10个带符号数(补码),将负数去掉,正数按原序排列,并显示正数。
思路:如果一个长度为一个字节的十六进制数高位为大于9的数,那这个数就是负数,所以遍历整个数组,判断每个十六进制数的高位大小,跳过负数,输出正数。
Data segment
num db 0AAH,01H,02H,0ABH,03H,04H,05H,06H,07H,0FFH
count db 10
Data ends
Code segment
assume cs:Code,ds:Data
start:
mov ax,Data
mov ds,ax
xor bl,bl
xor cx,cx ; to 0
mov cl,count
mov si,0
; 筛选正数并输出
next:
mov bl,num[si]
rcl bl,1
jc lop
; output
; 十位
mov bl,num[si]
shr bl,1
shr bl,1
shr bl,1
shr bl,1
and bl,0FH
mov dl,bl
cmp dl,09H
ja big1
add dl,30H
jmp outt1
big1:
add dl,36H
outt1:
mov ah,02H
int 21H
; 个位
mov bl,num[si]
and bl,0FH
mov dl,bl
cmp dl,09H
ja big2
add dl,30H
jmp outt2
big2:
add dl,36H
outt2:
mov ah,02H
int 21H
; 输出H
mov dl,'H'
mov ah,02H
int 21H
lop:
inc si
loop next
mov ah,4cH
int 21H
Code ends
end start
运行结果:
4. 试编写一个汇编语言程序,要求从键盘接收一个四位的十六进制数,并在终端显示与它等值的二进制数。
code segment
assume cs:code
start:
mov bx,0
mov ch,4
mov cl,4
s0:
mov ah,1 ;输入4个16进制数
int 21h
cmp al,39h ;判断 0~9 or A~H
jbe next
sub al,07h
next:
sub al,30h
shl bx,cl
add bl,al
dec ch
jnz s0
mov cx,16
;显示
mov dl,0AH ;换行
mov ah,02H
int 21H
s1:
mov dl,0
rol bx,1 ;最高位入CF
adc dl,30h
mov ah,02h
int 21h
loop s1
mov ax,4c00h
int 21h
code ends
end start
运行结果:
5. 试编写一个程序,要求比较数组ARRAY中的三个16位补码数,并根据比较结果在终端上显示如下信息
(1)如果三个数都不相等则显示0;
(2)如果三个数有两个数相等则显示1;
(3)如果三个数都相等,则显示2.
Data segment
ARRAY DW 1,2,3
Data ends
Code segment
assume cs:Code,ds:Data
Main PROC FAR
start:
MOV AX,DATA
MOV DS,AX
MOV AX,word ptr ARRAY
MOV BX,word ptr ARRAY[2]
CMP AX,word ptr ARRAY[2]; AB比较
je AB_E
CMP AX,word ptr ARRAY[4]; AC比较
je AC_E
CMP BX,word ptr ARRAY[4]; BC比较
je BC_E
MOV dl,30H
JMP EXIT
AB_E:
CMP BX,word ptr ARRAY[4]; BC比较
je BC_E2
MOV dl,31H
JMP EXIT
AC_E:
MOV dl,31H
JMP EXIT
BC_E:
MOV dl,31H
JMP EXIT
BC_E2:
MOV dl,32H
JMP EXIT
EXIT:
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
Code ends
Main endp
end start
运行结果:
子程序设计
1. 求1+2+3+……n的和,并以十进制数形式显示此数。
data segment
decnum db 5 dup(?)
data ends
code segment
assume cs:code,ds:data
main proc far
start:
mov ax,data
mov ds,ax
mov cx,20 ;从1加到xxx
call sumfunc ;使用cx寄存器传参,bx存返回值
call printfunc
mov ah,4ch
int 21h
main endp
sumfunc proc near
xor bx,bx
xor ax,ax
lop:
add ax,1
add bx,ax
loop lop
ret
sumfunc endp
printfunc proc near
LEA SI,DECNUM ;偏移地址传送
MOV DX,0
MOV AX,BX
MOV CX,10000
DIV CX
MOV [SI],AL ;求得万位的值,存入指定单元
INC SI
MOV AX,DX ;上次计算的余数存在DX中
MOV DX,0
MOV CX,1000
DIV CX
MOV [SI],AL ;求得千位的值,存入指定单元
INC SI
MOV AX,DX
MOV DX,0
MOV CX,100
DIV CX
MOV [SI],AL ;求得百位的值,存入指定单元
INC SI
MOV AX,DX
MOV CL,10
DIV CL
MOV [SI],AL ;求得十位的值,存入指定单元
INC SI
MOV [SI],AH ;存个位的值
LEA SI,DECNUM
;开始显示存储单元中的十进制数
MOV CX,5
DISP:
MOV DL,[SI] ;依次取出十进制数各位的值
OR DL,30H ;将取出的值转换为ASCII值
MOV AH,2
INT 21H ;利用DOS功能调用,显示
INC SI
LOOP DISP
MOV DL,'D'
MOV AH,2
INT 21H
ret
printfunc endp
code ends
end start
运行结果:
2. 从键盘输入一个十进制数然后以十六进制输出
DATA SEGMENT
NUM10 DB 5;定义缓冲区长度
DB ?;实际输入字符个数的计数单元
DB 5 DUP(0)
NUM16 DB 4 DUP(?)
ENDSING DB '$'
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA,CS:CODE
MAIN PROC FAR
START:
MOV AX,DATA
MOV DS,AX
CALL INPUT
CALL TURN
CALL PRINT16
MOV AH,4CH ;返回dos
INT 21H
MAIN ENDP
TURN PROC NEAR
XOR BX,BX
XOR AX,AX
XOR CX,CX
MOV CL,BYTE PTR [NUM10+1]
MOV SI,2
MOV DI,0AH
LOP1:
MUL DI
MOV BL,BYTE PTR NUM10[SI]
SUB BL,30H
ADD AX,BX
INC SI
LOOP LOP1
;到这里ax存了输入的数
;接下来转换16进制存入num16地址单元
MOV CL,04H
MOV CH,04H
MOV SI,0
LOP2:
XOR BX,BX ;清空bx
;位移ax
ROL AX,CL
MOV BL,AL
AND BL,0FH
CMP BL,09H
JA ZIMU
CONTI:
ADD BL,30H
MOV NUM16[SI],BL ;储存
INC SI
DEC CH
JNZ LOP2
RET ;循环结束推出子程序
ZIMU: ;转字母
ADD BL,07H
JMP CONTI
TURN ENDP
INPUT PROC NEAR
LEA DX,NUM10
MOV AH,0AH
INT 21H
RET
INPUT ENDP
PRINT16 PROC NEAR
MOV AH,02H
MOV DL,0DH ;回车
INT 21H
MOV AH,02H
MOV DL,0AH ;换行
INT 21H
LEA DX,NUM16
MOV AH,09H
INT 21H
MOV AH,02H
MOV DL,'H' ;'H'
INT 21H
RET
PRINT16 ENDP
CODE ENDS
END START
运行结果:
-
练习题目
这里我就不分章节了,只记录一些比较难懂的题目。
1. 在汇编语言程序中,对END语句的叙述正确的是( C )。
A、END语句是一可执行语句
B、END语句表示程序执行到此结束
C、END语句表示源程序到此结束
D、END语句在汇编后要产生机器码
2. 假设OP1,OP2是已经用DB定义的变量,判断指令格式是否正确
CMP 15, BX (x)
CMP OP1, OP2(x)
CMP AX, OP1(x)
CMP OP1, 25(√)
3. 假设VAR1和VAR2为字变量,LAB为标号
JMP LAB [SI](x)
JNZ VAR1(x)
4. 语句LENGTH=SIZE*TYPE是合法的。(x)
5. 指出下列指令的错误原因,假设下列指令中的所有标识符均为类型属性为字的变量
(1) MOV AH, BX
数据类型不一致
(2) MOV AX, [SI][DI]
只有变址+基址寻址方式,没有变址+变址寻址方式
(3) MOV BYTE PTR [BX], 1000
立即数和指定的操作数类型不一致,指定为字节操作,1000为字类型
(4) MOV CS, AX
CS代码段寄存器,该寄存器只能由系统管理
(5) MOV WORD_OP1, WORD_OP2
不允许两个内存单元直接传递数据
(6) MOV AX, WORD_OP1+WORD_OP2
两个内存单元地址相加没有意义
(7) SUB [BX],2
未指定数据类型
6. 8086/8088系统中,存储器是分段组织的,存储器物理地址计算式是( B )
A、段地址+偏移地址
B、段地址*10H+偏移地址
C、段地址*16H+偏移地址
D、段地址+10H*偏移地址
7. 溢出标志可以用来判断运算的结果是否产生溢出。(X)
溢出标志指CF标志位,但是有些运算不是靠CF标志溢出
8. 对于有符号的数来说,下列哪个值最大(D )
A、0F8H
B、11010011B
C、82
D、123Q
AB是负数,对于A第一个0是因为汇编中的16进制不允许用字母开头,故A其实就是F8H。