实验4
task 1
验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。
在debug环境中,分别实践、观察:
① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
add 指令对 零标志位ZF(Zero Flag) 位有影响,对进位标志位CF(Carry Flag)也有影响。
② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
inc指令只会对零标志位ZF(Zero Flag) 位产生影响, 对进位标志位CF(Carry Flag)不会产生影响。
使用任意文本编辑器,录入8086汇编源task1.asm。
1 assume cs:code, ds:data 2 3 data segment 4 x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h 5 y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h 6 data ends 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, offset x 12 mov di, offset y 13 call add128 14 15 mov ah, 4ch 16 int 21h 17 18 add128: 19 push ax 20 push cx 21 push si 22 push di 23 24 sub ax, ax 25 26 mov cx, 8 27 s: mov ax, [si] 28 adc ax, [di] 29 mov [si], ax 30 31 inc si 32 inc si 33 inc di 34 inc di 35 loop s 36 37 pop di 38 pop si 39 pop cx 40 pop ax 41 ret 42 code ends 43 end start
add128是子程序子程序,功能:实现计算两位128位数的加法
入口参数:
- ds:si指向存储第一个128位数的存储空间(因为一个数128位,需要8个字节的连续空间)
- ds:di指向存储第二个128位数的存储空间
出口参数:
- 加运算后的结果,保存在第一个数的存储空间中,即:ds:si开始的连续8个字节空间
在代码段种,调用add128实现对标号x和y处存储的两个128位数据相加,结果保存在x处的连续128个字节中。
对程序进行汇编、链接,得到可执行程序task1.exe。在debug中调试程序,回答问题:
① line31-line34的4条inc指令,能否替换成如下代码?
1 add si, 2 2 add di, 2
不能:因为add si, 2、add di, 2指令会对进位标志位CF产生影响,导致影响最后结果,而原文的inc指令不会影响CF的值。但是在此题中没有涉及到影响。
② 在debug中调试,观察数据段中做128位加之前和加之后,数据段的值的变化。
前:
后:
task2
使用任意文本编辑器,录入8086汇编源码task2.asm:
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 s1: 12 mov ah, 1 13 int 21h 14 mov [si], al 15 cmp al, '#' 16 je next 17 inc si 18 jmp s1 19 next: 20 mov ah, 2 21 mov dl, 0ah 22 int 21h 23 24 mov cx, si 25 mov si, 0 26 s2: mov ah, 2 27 mov dl, [si] 28 int 21h 29 inc si 30 loop s2 31 32 mov ah, 4ch 33 int 21h 34 code ends 35 end start
对源程序task2.asm进行汇编、链接,得到可执行文件task2.exe。
运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结果。
结合运行结果,理解代码并回答问题:
① 汇编指令代码line11-18,实现的功能是:
读入一个字符,判断输入字符是否等于 #,若不等于则存入DS偏移地址为si的位置, si 计数,并继续读入;若等于#,则条件指令je,跳转到标记next处。
② 汇编指令代码line20-22,实现的功能是?
输出换行符(ASCII码中换行符即为0AH),在下一行开始输出字符串。
③汇编指令代码line24-30,实现的功能是?
将读入字符串长度,使用 loop 输出先前数据段中的字符串,从而实现记录输入语句的功能。
说明:task2.asm中用到的两个DOS系统功能调用: DOS系统功能调用int 21h的1号子功能 功能:从键盘上输入单个字符 入口参数:(ah) = 1 出口参数: (al)存放输入字符的ASCⅡ码 即:1 mov ah, 1 2 int 21h ; (al) <-- 输入字符的ascⅡ码DOS系统功能调用int 21h的2号子功能 功能:输出单个字符到屏幕上 入口参数:(ah) = 2, (dl) = 待输出的字符或其ascⅡ码 出口参数:无 即:
1 mov ah, 2 2 mov dl, ×× ; ××是待输出的字符,或,其ascⅡ码 3 int 21h
3. 实验任务 3
针对8086CPU,已知逻辑段定义如下:1 data segment 2 x dw 91, 792, 8536, 65521, 2021 3 len equ $ - x 4 data ends编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据之间以空格间隔。 要求: 编写子程序printNumber 功能:以十进制形式输出一个任意位数的整数(整数范围0 ~ 65535) 入口参数:寄存器ax(待输出的数据 --> ax) 出口参数:无 编写子程序printSpace 功能:打印一个空格 入口参数:无 出口参数:无 在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。
1 assume cs:code, ds:data 2 3 data segment 4 x dw 91, 792, 8536, 65521, 2021 5 len equ $ - x 6 data ends 7 8 code segment 9 10 printNumber: 11 push bx 12 push di 13 push cx 14 mov cx,0 ; 计数器,控制输出循环次数 15 mov di,0 16 s1:mov dx,0 17 mov bx,10 18 div bx ; 除数(十进制),每次除以10得到单独数位上的数字 19 or dl,30h 20 push dx ;得到余数进栈 21 inc di 22 cmp ax,0 ; 被除数为0时结束计算,跳出循环 23 jne s1 24 mov cx,di 25 s2:pop dx 26 mov ah,2 27 int 21h 28 loop s2 29 30 pop cx 31 pop di 32 pop bx 33 ret 34 35 printSpace: 36 mov ah,2 37 mov dl,20h ;转为ASCII值打印 38 int 21h 39 ret 40 41 start: 42 mov ax, data 43 mov ds, ax 44 45 mov cx, len 46 mov di, offset x 47 s: mov ax, [di] 48 call printNumber 49 call printSpace 50 add di, 2 51 sub cx, 1 52 loop s 53 54 mov ax, 4c00h 55 int 21h 56 57 code ends 58 59 end main
运行结果:
4. 实验任务4
针对8086CPU,已知逻辑段定义如下:1 data segment 2 str db "assembly language, it's not difficult but tedious" 3 len equ $ - str 4 data ends编写8086汇编源程序task4.asm,将data段中字符串里的小写字符转换成大写。 要求: 编写子程序strupr 功能:将包含任意字符的字符串中的小写字母变成大写 入口参数 (ds:si ) 字符串首地址的段地址和偏移地址分别送至ds和si (cx) 字符串的长度 出口参数:无 在主体代码中,设置入口参数,调用strupr, 实现题目要求。
1 assume cs:code,ds:data 2 data segment 3 str db "assembly language, it's not difficult but tedious" 4 len equ $ - str 5 data ends 6 7 code segment 8 start: 9 mov ax,data 10 mov ds,ax 11 12 mov cx,len 13 mov si,offset str 14 s1: 15 call strupr 16 inc si 17 loop s1 18 19 mov ah,4ch 20 int 21h 21 22 strupr: 23 mov al,[si] 24 cmp al,'a' 25 jb s2 ; jump below 小于“a” 26 cmp al,'z' 27 ja s2 ; jump above 大于“z” 28 and byte ptr [si],11011111b 29 s2: 30 ret 31 32 code ends 33 end start
测试结果:
5. 实验任务5
使用任意文本编辑器,录入8086汇编源码task5.asm。1 assume cs:code, ds:data 2 3 data segment 4 str1 db "yes", '$' 5 str2 db "no", '$' 6 data ends 7 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 13 mov ah, 1 14 int 21h 15 16 mov ah, 2 17 mov bh, 0 18 mov dh, 24 19 mov dl, 70 20 int 10h 21 22 cmp al, '7' 23 je s1 24 mov ah, 9 25 mov dx, offset str2 26 int 21h 27 28 jmp over 29 30 s1: mov ah, 9 31 mov dx, offset str1 32 int 21h 33 over: 34 mov ah, 4ch 35 int 21h 36 code ends 37 end start
对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。 运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。 说明:task5.asm中,使用用到的DOS系统功能调用和BIOS中断例程 DOS系统功能调用int 21h的1号子功能 功能:从键盘上输入单个字符 入口参数:(ah) = 1 出口参数: (al)存放输入字符的ASCⅡ码 即:
1 mov ah, 1 2 int 21h ; (al) <-- 输入字符的ascⅡ码DOS系统功能调用int 21h的9号子功能 功能:显示字符串 入口参数:(ah) = 9,(ds:dx) = 字符串的首地址的段地址和偏移地址 出口参数: 无 其它要求:字符串必须以$结束 即:
1 mov ah, 9 2 mov ds, ×× ; ××是待输出字符串所在段的段地址 3 mov dx, ×× ; ××是待输出字符串第一个字符的偏移地址 4 int 21hBIOS中断例程int 10h的2号子功能 功能:设置光标位置 入口参数:(ah) = 2, (bh) = 页号(默认取0), (dh) = 行号, (dl) = 列号 出口参数:无 即:
1 mov ah, 2 2 mov bh, ×× ; ××是页号 3 mov dh, ×× 4 mov dl, ×× ; ××是列号 5 int 10h实验:输入“7”,观察结果 ,发现屏幕上输出“yes”字符串;
输入其他字符,如“1”、“2”,观察都只能得到屏幕上输出的字符串“no”:
分析源码,得到task5的功能为:分析输入的字符,如果为“7”,则在屏幕上输出“yes”字符串;如果不为“7”而是其他任何数字,都只能得到屏幕上输出字符串“no”。
实验6
实验任务1、2、3、5中使用了不少系统提供的中断例程。本实验任务中,要求自行实现一个42号软中断例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to 2049!"。
1 ; task6_1.asm 2 assume cs:code 3 4 code segment 5 start: 6 ; 42 interrupt routine install code 7 mov ax, cs 8 mov ds, ax 9 mov si, offset int42 ; set ds:si 10 11 mov ax, 0 12 mov es, ax 13 mov di, 200h ; set es:di 14 15 mov cx, offset int42_end - offset int42 16 cld 17 rep movsb 18 19 ; set IVT(Interrupt Vector Table) 20 mov ax, 0 21 mov es, ax 22 mov word ptr es:[42*4], 200h 23 mov word ptr es:[42*4+2], 0 24 25 mov ah, 4ch 26 int 21h 27 28 int42: 29 jmp short int42_start 30 str db "welcome to 2049!" 31 len equ $ - str 32 33 ; display string "welcome to 2049!" 34 int42_start: 35 mov ax, cs 36 mov ds, ax 37 mov si, 202h 38 39 mov ax, 0b800h 40 mov es, ax 41 mov di, 24*160 + 32*2 42 43 mov cx, len 44 s: mov al, [si] 45 mov es:[di], al 46 mov byte ptr es:[di+1], 2 47 inc si 48 add di, 2 49 loop s 50 51 iret 52 int42_end: 53 nop 54 code ends 55 end start
1 ; task6_2.asm 2 assume cs:code 3 4 code segment 5 start: 6 int 42 7 8 mov ah, 4ch 9 int 21h 10 code ends 11 end start
运行结果:输出“welcom to 2049!”
程序功能:实现软中断:软中断是由程序中的int指令引起的。如果设置了中断程序,则必须将其添加到中断向量表中,即程序的输入地址。如果在程序执行过程中int指令导致中断,CPU将接收中断号,获得中断段条目的段地址和偏移地址,继续中断程序。