实验13(1)
(1)编写并安装int 7ch中断例程,功能为显示一个用0结尾的字符串,中断例程安装在0:200处。
参数: (dh)=行号, (dl)=列号, (cl)=颜色 ds:si指向字符串首地址
以上中断例程安装好后,对下面的程序进行单步跟踪,尤其注意int,iret指令执行前后cs,ip的和栈中的状态。
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
| assume cs:code
data segment
db 'Welcome to masm!', 0
data ends
code segment
start: mov dh, 10
mov dl, 10
mov cl, 2
mov ax, data
mov ds, ax
mov si, 0
int 7ch
mov ax, 4c00H
int 21H
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
| assume cs:code
code segment
start:
mov ax, cs
mov ds, ax
mov si, offset show_str
mov ax, 0000H
mov es, ax
mov di, 200H
mov cx, offset show_strend - offset show_str
cld
rep movsb
mov ax, 0000H
mov es, ax
mov word ptr es:[7cH*4], 200H
mov word ptr es:[7cH*4+2], 0000H
mov ax, 4c00H
int 21H
show_str: push dx
push cx
push si
mov ax, 0b800H
mov es, ax
mov ax, 0
mov al, 160
mul dh
mov bx, ax
mov ax, 0
mov al, 2
mul dl
add bx, ax
mov di,0
mov al, cl
mov ch, 0
show: mov cl, ds:[si]
jcxz ok
mov es:[bx+di+0], cl
mov es:[bx+di+1], al
add di, 2
inc si
jmp short show
ok: pop si
pop dx
pop cx
iret
show_strend:nop
code ends
end start
|
实验13(2)
编写并安装int 7ch中断例程,功能为完成loop指令的功能。
参数:(cx)=循环次数,(bx)=位移。
以上中断例程安装好后,对下面的程序进行单步跟踪,尤其注意int,iret指令执行前后cs,ip的和栈中的状态。
实验目的:
测试调用代码如下:
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
| assume cs:code
code segment
start: mov ax, 0b800H
mov es, ax
mov di, 160*12
mov bx, offset s – offset se
mov cx, 80
s: mov byte ptr es:[di], '!'
add di, 2
int 7cH
se: nop
mov ax, 4c00H
int 21H
code ends
end start
|
程序分析:
(1)编写一个7cH的中断例程,实现loop语句的功能。通过以上实例,我们发现int 7cH实现的功能就是loop指令的功能。如果(cx)不等于0,跳转到s标号继续执行。并且调用一次int 7cH,(cx)=(cx)-1(每次).
(2)7cH的入口参数:cx、bx(我们规定的),cx代表计数器,bx代表了相对位移。因为中断例程不是返回到操作系统,故它必然包含iret指令,返回到调用那一点。
(3)回忆loop指令,它的相对位移是:从标号s(按照本例子来说)- loop指令下面那个指令的首地址(也就是se标号的地址)。由于int 7cH就等价于loop指令,那么它入口参数也需要相对的位移,这个相对位移就是(bx)=offset s – offset se。这里se标号与前面2个例程用途不一样了,它不用作计算例程的长度了,它代表了se标号的地址,用于计算相对位移了。
(4)我们来看看例程中,怎样实现将(cx)=(cx)-1(每次);跳转到s标号处,直到(cx)=0。跳转到s标号,肯定是修改了ip了。至于cs也应该修改,虽然它在一个段内。产生的结果是:(ip)=s标号的ip,(cs)=s标号的cs。
(5)在调用7cH例程时,cs和ip都压栈了,cs值是s标号的cs,ip的值应该是标号se的偏移地址。那么在栈中,有了s标号的cs了,偏移地址是se的偏移地址。怎样把计算出s的偏移地址,这个例程的任务就完成了。
(6)我们可以利用iret指令。回忆iret指令,(执行iret指令,用汇编描述的过程是:pop ip;pop cs;popf,与我们引发中断过程中CPU执行的入栈过程(pushf;push cs;push ip)正好是相对应的。)popf弹栈状态寄存器值,我们不讨论了。这里主要讨论ip和cs,cs肯定是s标号的cs了,我们现在想法把栈中的ip值(栈中的值为se标号的值)修改为offset se +(bx)那么它肯定就是s标号的地址值。最后在弹栈,实现(cs)=s标号的cs,(ip)=s标号的ip了。
(7)回忆栈结构,此例中是使用的系统自动的栈(这个我喜欢,但也不要蒙圈了。)ss代表栈的段地址。bp默认是偏移地址,也就是说ss:[bp]就代表了栈空间的bp单元。sp是栈顶的指针。在8086中,一个栈的基本单元是2个字节的。以上分析都有了清晰的认识后,我们来看看这个例程代码:
(8)例程代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
| lp: push bp
mov bp, sp
dec cx
jcxz lpret
add [bp+2], bx
lpret: pop bp
iret
|
程序分析:
【1】因为ss和bp是配套使用的,[bp]代表ss栈中单元,bp也就是ss的偏移地址。push bp目的是保护bp的值,因为下面将会用到bp变量。
【2】mov bp, sp将栈顶指针sp送入到bp;此时栈中的数据有(从栈顶开始依次向下),bp的值(刚压入的),ip值(int 7cH调用时的,应该是se标号的值),cs值(int 7cH调用时的,应该和s标号的值一样的),flag值(int 7cH调用时的,标志寄存器的值,这个我们不考虑)。【3】dec cx; 我们为了实现loop的功能,在例程中应该是执行一次循环(调用一次7cH,):cx的值就减1。
【4】jcxz lpret ;与(cx)值判断,如果为0,跳转到lpret标号,
【5】add [bp+2], bx 由于栈结构栈顶是低地址,我们想修改从栈顶向下第2个单元,也就是bp+2(此时bp=sp);那么[bp+2]就代表了栈中从栈顶开始的第2个单元。正好,这个单元就是iret弹栈的ip的值。此时[bp+2]值是offset se,再加上一个相对偏移量bx,此时的[bp+2]=offset se+(bx);也就是offset s的值。
【6】pop bp ;恢复bp值
【7】iret ;pop ip ,pop cs ,popf
装载程序代码如下:
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
| assume cs:code
code segment
start:
mov ax, cs
mov ds, ax
mov si, offset lp
mov ax, 0000H
mov es, ax
mov di, 200H
mov cx, offset lpend - offset lp
cld
rep movsb
mov ax, 0000H
mov es, ax
mov word ptr es:[7cH*4], 200H
mov word ptr es:[7cH*4+2], 0000H
mov ax, 4c00H
int 21H
lp: push bp
mov bp, sp
dec cx
jcxz lpret
add [bp+2], bx
lpret: pop bp
iret
lpend: nop
code ends
end start
|
实验13(3)
分别在屏幕的第2、4、6、8行显示4句英文诗,补全程序。
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
| assume cs:code
code segment
s1: db 'Good,better,best,','$'
s2: db 'Never let it rest,','$'
s3: db 'Till good is better,','$'
s4: db 'And better,best.','$'
s: dw offset s1, offset s2, offset s3, offset s4
row: db 2, 4, 6, 8
start :
mov ax, cs
mov ds, ax
mov bx, offset s
mov si, offset row
mov cx, 4
ok:
mov bh,0 mov dh, [si]
mov dl, 0
mov ah, 2
int 10h
mov dx,[bx]
mov ah,9
int 21h
inc si
add bx,2
loop ok
mov ax,4c00h
int 21h
code ends
end start
|