do0程序的主要任务是显示字符串,程序如下/strong>
do0:
设置 ds:si 指向字符串
mov ax,0b800h
mov es,ax
mov di,12*160+36*2 ;设置 es:di 指向显存空间的中间位置
mov cx,9 ;设置 cx 为字符串长度
s:
mov al,[si]
mov es:[di],al
inc si
add di,2
loop s
mov ax,4c00h
int 21h
do0end: nop
程序写好了,可要显示的字符串放在那里呢?我们看下面的程序
assume cs:code
data segment
db "overflow"
data ends
code segment
start:
mov ax,cs
mov ds,ax
mov si,offset do0
mov ax,0
mov es,ax
mov di,200h
mov cx,offset do0end-offset do0
cld
rep movsb
设置中断向量表
mov ax,4c00h
in 21h
do0: mov ax,data
mov ds,ax
mov si,0
mov ax,0b800h
mov es,ax
mov di,12*160+36*2
mov cx,9
s: mov al,[si]
mov es:[di],al
inc si
add di,2
loop s
do0end:nop
end start
上面的程序,看似合理,可实际上却大错特错。注意,"overflow !”在程序12.2的data段中。程序12.2执行完成后返回,它所占用的内存空间被系统释放,而在其中存放的“overflow!”也将很可能被别的信息覆盖。而do0程序被放到了0:200处,随时都会因发生了除法溢出而被CPU执行,很难保证do0程序从原来程序12.2所处的空间中取得的是要显示的字符串“overflow! "。
因为do0程序随时可能被执行,而它要用到字符串“overflow! ",所以该字符串也应该存放在一段不会被覆盖的空间中。正确的程序如下。
assume cs:code
data segment
db "overflow"
data ends
start:
mov ax,cs
mov ds,ax
mov si,offset do0 ;设置ds:si指向源地址
mov ax,0
mov es,ax
mov di,200h ;设置es:di指向目的地址
mov cx,offset do0end-offset do0 ;设置cx的传输长度
cld ;设置传输方向为正
rep movsb
设置中断向量表
mov ax,4c00h
in 21h
do0:jmp short do0start
db"overflow!"
do0start: mov ax,data
mov ds,ax
mov si,202h ;设置 ds:si 指向字符串
mov ax,0b800h
mov es,ax
mov di,12*160+36*2 ;设置 es:di 指向显存空间的中间位置
mov cx,9 ;设置 cx 为字符串长度
s: mov al,[si]
mov es:[di],al
inc si
add di,2
loop s
mov ax,4c00h
int 21h
do0end:nop
code ends
end start
在程序中,将“overflow!”放到do0程序中,程序12.3执行时,将标号do0到标号do0end之间的内容送到0000:0200处。 注意,因为在do0程序开始处的“overflow!”不是可以执行的代码,所以在" overflow !”之前加上一条jmp指令,转移到正式的do0程序。当除法溢出发生时,CPU执行0:200处的jmp指令,跳过后面的字符串,转到正式的do0程序执行。 do0程序执行过程中必须要找到“overflow! ",那么它在哪里呢?首先来看段地址,"overflow!”和do0的代码处于同一个段中,而除法溢出发生时,CS中必然存放do0的段地址,也就是“overflow!”的段地址;再来看偏移地址,0:200处的指令为jmp shortdo0start,这条指令占两个字节,所以“overflow!”的偏移地址为202h
