实验任务1
(1)验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。 在debug环境中,分别实践、观察:
① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
在debug环境中输入如上指令,发现add指令对零标志位和进位标志位都有影响。
在debug中输入如上指令,发现inc指令对零标志位有影响,但是对进位标志位没有影响。
(2)使用任意文本编辑器,录入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
对程序进行汇编、链接,得到可执行程序task1.exe。在debug中调试程序,并回答问题。
① line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?
1 add si, 2 2 add di, 2
② 在debug中调试,观察数据段中做128位加之前,和,加之后,数据段的值的变化。
查看数据段中的数据,进行add128后查看,发现结果如下
把inc替换成add,结果和上图一样。
所以只对这组数据而言,将inc替换成add是可行的,因为add指令没有产生任何进位,所以不会对标志寄存器的进位寄存器的值产生影响,也就不会影响adc指令的结果。
但本质上是不可以替换的,inc和add对进位寄存器的影响不同,如果si或者di的值在本次计算中产生了进位,它会对adc指令产生影响。
实验任务二
使用任意文本编辑器,录入8086汇编源码task2.asm。
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 code segment 6 start: 7 mov ax, data 8 mov ds, ax 9 mov si, 0 10 s1: 11 mov ah, 1 12 int 21h 13 mov [si], al 14 cmp al, \'#\' 15 je next 16 inc si 17 jmp s1 18 next: 19 mov ah, 2 20 mov dl, 0ah 21 int 21h 22 mov cx, si 23 mov si, 0 24 s2: mov ah, 2 25 mov dl, [si] 26 int 21h 27 inc si 28 loop s2 29 mov ah, 4ch 30 int 21h 31 code ends 32 end start
对源程序task2.asm进行汇编、链接,得到可执行文件task2.exe。
运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结果。结合运 行结果,理解代码并回答问题:
运行结果如下,程序的目的是输出#之前输入的字符到屏幕上。
① 汇编指令代码line11-18,实现的功能是?
通过键盘输入一个字符存储进al中,并将它存储到ds:[si]中,然后拿这个字符和#号进行比较,如果为#就跳转到next代码段,否则数据段偏移地址加一,回到开头继续存储键盘输入的字符。
② 汇编指令代码line20-22,实现的功能是?
输出一个换行到屏幕上。
③ 汇编指令代码line24-30,实现的功能是?
通过循环,将数据段中存储的从键盘中输入的字符输出到屏幕上,由于#作为跳转的条件并没有存入数据段中,所以#不会被输出。
实验任务三
针对8086CPU,已知逻辑段定义如下:
1 data segment 2 x dw 91, 792, 8536, 65521, 2021 3 len equ $ - x 4 data ends
编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据 之间以空格间隔。
代码:
1 assume ds:data, cs:code 2 3 data segment 4 x dw 91, 792, 8536, 65521, 2021 5 len equ $ - x 6 data ends 7 8 9 code segment 10 start: 11 mov cx,5 12 mov ax,data 13 mov ds,ax;ds作数据段 14 mov si,0 15 16 s: 17 mov dx,0;初始化处理dx作为高位为0 18 mov ax,ds:[si];初始化ax 19 20 call printNumber;打印一个16位数 21 call printSpace;打印一个空格 22 23 inc si 24 inc si;字数据占两个字节 25 loop s 26 27 mov ax,4c00h 28 int 21h 29 30 printNumber: 31 push cx;cx存的数之后也要用,先存起来 32 mov cx,0;cx用来计算出栈的数字个数 33 34 s1: 35 mov bx,10 36 div bx;除以10,余数在DX里,商在AX中 37 push dx;dx入栈 38 inc cx;入栈的数字加一 39 cmp ax,0;ax和0做比较 40 je next;商为0跳转到next 41 42 mov dx,0 43 jmp s1 44 45 next: 46 pop bx;出栈存给bx,因为每次只有一个数,所以高位存0,低位存数字 47 48 mov ah,2;调用中断2号子功能 49 mov dl,bl;只有低位存数字,只把bl给dl即可,bh里是0 50 add dl,30h;加30将数字转变成字符 51 int 21h 52 loop next;循环直到所有数字都已经输出 53 54 pop cx 55 ret 56 57 58 printSpace: 59 mov ah,2 60 mov dl,\' \' 61 int 21h 62 ret 63 64 code ends 65 end start
效果:
在debug环境中运行,发现已经将数字显示到屏幕上。
实验任务四
针对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;ds作为数据段 11 mov si,0 12 mov cx,len;记录循环次数 13 call strupr 14 mov ah, 4ch 15 int 21h 16 17 strupr: 18 mov al,[si] 19 cmp al,\' \' ;和空格作比较 20 je s1;如果是空格就跳过and操作 21 cmp al, \',\' ;和逗号作比较 22 je s1;如果是逗号就跳过and操作 23 cmp al, 00100111B;和单引号比较 24 je s1;如果是单引号就跳过and操作 25 and al,0dfh 26 s1: 27 mov [si],al;反存入内存 28 inc si 29 loop strupr 30 31 32 code ends 33 end start
在debug环境中运行,查看运行前后的数据段内的信息,发现已经成功将数据变为大写
实验任务五
使用任意文本编辑器,录入8086汇编源码task5.asm。
对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。
运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。
代码:
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
效果:
输入7:
不输入7:
程序的功能:
从功能上来说,程序的功能是输入7会在屏幕上输出一个yes,输入7以外的字符会在屏幕上输出一个no
从代码上来说,程序首先接受键盘输入的字符,随后设置光标在屏幕上的位置(也就是字符串在屏幕上显示的位置)然后拿这个字符和字符‘7’进行比较,如果比较成功就会跳入s1函数在屏幕上输出str1也就是yes。如果比较不成功就会顺序执行在屏幕上输出str2的字符串也就是no。
实验任务六
实验任务1、2、3、5中使用了不少系统提供的中断例程。
本实验任务中,要求自行实现一个42号软中断 例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to 2049!"。
代码:
1 assume cs:code 2 3 code segment 4 start: 5 ; 42 interrupt routine install code 6 mov ax, cs 7 mov ds, ax 8 mov si, offset int42 ; set ds:si 9 10 mov ax, 0 11 mov es, ax 12 mov di, 200h ; set es:di 13 14 mov cx, offset int42_end - offset int42 15 cld 16 rep movsb 17 18 ; set IVT(Interrupt Vector Table) 19 mov ax, 0 20 mov es, ax 21 mov word ptr es:[42*4], 200h 22 mov word ptr es:[42*4+2], 0 23 24 mov ah, 4ch 25 int 21h 26 27 int42: 28 jmp short int42_start 29 str db "welcome to 2049!" 30 len equ $ - str 31 32 ; display string "welcome to 2049!" 33 int42_start: 34 mov ax, cs 35 mov ds, ax 36 mov si, 202h 37 38 mov ax, 0b800h 39 mov es, ax 40 mov di, 24*160 + 32*2 41 42 mov cx, len 43 s: mov al, [si] 44 mov es:[di], al 45 mov byte ptr es:[di+1], 2 46 inc si 47 add di, 2 48 loop s 49 50 iret 51 int42_end: 52 nop 53 code ends 54 end start
1 assume cs:code 2 code segment 3 start: 4 int 42 ; 调用自己实现的42号软中断 5 mov ah, 4ch 6 int 21h 7 code ends 8 end start
效果:
通过此项实现任务,你对中断、软中断实现机制的理解
中断也就是硬中断,通过硬件来实现对进程的强制中断,它可以直接中断CPU的执行。
软终端通过当前执行的程序来实现中断,它不可以直接中断CPU的执行。
程序通过使用int指令来触发软中断。
实验总结:
通过本次实验,提高了对汇编语言标志寄存器和软中断的理解。其中第一题和第二题通过观察代码,增加对标志寄存器的理解。
第一题中,inc指令和add指令对零标志位都有影响,但是inc操作对进位标志位没有影响,再加上adc指令除了add后面的内存单元或立即数外,还会加上进位标志位的位数,但第一题里因为没有产生进位,所以看起来答案是一样的,但本质inc和add是不一样的。由此衍生出第一题的核心内容。
第二题的核心在于cmp al, \'#\'和 je next这两条指令,cmp是通过做没有存储结果的减法来对标志寄存器进行操作,je是通过判断标志寄存器中的数值来进行是否跳转的判断,这两条本质可以理解为高级语言中的if操作。
第三第四题是通过对上面两道题的理解,来进行自己的编程实现。第三题通过判断商是否为0作为跳转条件,以此实现位数不确定的数值的打印,这是对上一次实验内容的衍生。第四题比第三题相对容易,只是对内存单元进行操作,这里不再赘述。
另外在上面四题中,应用了中断的功能来实现在屏幕上打印内容或者输入内容,由此开启第五题和第六题的题目。第五题和第六题通过几个代码对系统自带的中断指令和自己写的中断指令进行结合理解,让还没有学习中断内容的我能够自我预习了解了一部分内容,提高了下次课程的效率。