请注意,里面有程序和测试程序,例如 exp1303.asm指的是13章第三个题目,exp1303t.asm指的是对exp1303程序的测试。。。
; exp1301.asm
; 安装中断7ch的中断例程
; 功能:求一个word型数的平方
;
;
assume cs:code
code segment
start:
; 拷贝代码到非系统管理区
mov ax, cs
mov ds, ax
mov si, offset sqr ; 从cs段的sqr开始复制到0:200处
mov ax, 0
mov es, ax
mov di, 200h
mov cx, offset sqrend - offset sqr ; cx为需要复制的代码字节数
cld
rep movsb ; 调用 movsb 把 es:[di] 的字节拷贝到 ds:[si]
; 设置好中断向量
mov ax, 0
mov es, ax
mov word ptr es:[7ch*4], 200h ; 用 word ptr 指明是要拷贝一个字
mov word ptr es:[7ch*4+2], 0
mov ax, 3
int 7ch
mov ax, 4c00h
int 21h
sqr:
mul ax
iret
sqrend:
nop
code ends
end start
; exp1302.asm
; 安装7ch中断的中断例程
; 功能:实现将 ds:[si] 开始的字符串显示出来
assume cs:code
data segment
db "welcome to masm!", 0
data ends
code segment
start:
; 拷贝代码到非系统管理区
mov ax, cs
mov ds, ax
mov si, offset int7c ; 从cs段的int7c开始复制到0:200处
mov ax, 0
mov es, ax
mov di, 200h
mov cx, offset int7cend - offset int7c
cld
rep movsb
; 设置好中断向量
mov ax, 0
mov es, ax
mov word ptr es:[7ch*4], 200h
mov word ptr es:[7ch*4+2], 0
; dh = 行数,dl = 烈数,cl = 颜色,ds:si指向首地址
mov dh, 10
mov dl, 10
mov cl, 2
mov ax, data
mov ds, ax
mov si, 0
int 7ch
mov ah, 01h
int 21h
mov ax, 4c00h
int 21h
int7c:
push ax
push bx
push cx
push dx
push es
; 计算好字串开始显示的地址Y = 160*(行数-1) + 列数*2-2, B800 : Y
; 循环将参数里的字串写进显卡内存,并检测到0就返回
; bx = 160*(行数-1)
sub dh, 1h
mov al, 160
mul dh
mov bx, ax ; bx 为根据行数算出来的偏移值
; ax = 列数*2-2
mov al, 2
mul dl
sub ax, 2 ; 根据列数算出来的偏移值
add bx, ax ; 行数和列数的和存在bx中了
mov ax, 0b800h
mov es, ax
mov dl, cl ; 保存字体颜色属性
mov ch, 0
s_show_str:
mov cl, ds:[si]
mov es:[bx], cl
jcxz ok_show_str
mov es:[bx+1], dl
inc si
add bx, 2
jmp short s_show_str
ok_show_str:
pop es
pop dx
pop cx
pop bx
pop ax
iret
int7cend:
nop
code ends
end start
; exp1302t.asm
; 上一个程序的测试程序
; 测试 7ch 中断,显示字符串
assume cs:code
data segment
db "Welcome to masm 6.11!", 0
data ends
code segment
start:
mov ax, data
mov ds, ax
mov dh, 10
mov dl, 10
mov cl, 2
mov si, 0
int 7ch
mov ax, 4c00h
int 21h
code ends
end start
; exp1303.asm
; 安装7ch中断的中断例程
; 功能:实现将ds:si开始,0结束的字符串转化为全部转化为大写
assume cs:code
data segment
db "welcome to masm!", 0
data ends
code segment
start:
; 拷贝代码到非系统管理区
mov ax, cs
mov ds, ax
mov si, offset int7c ; 把中断代码从cs段的int7c开始复制到0:200处
mov ax, 0
mov es, ax
mov di, 200h
mov cx, offset int7cend - offset int7c
cld
rep movsb
; 设置好中断向量 0:200 处
mov ax, 0
mov es, ax
mov word ptr es:[7ch*4], 200h
mov word ptr es:[7ch*4+2], 0
mov ax, data
mov ds, ax
mov si, 0
int 7ch
mov ah, 01h
int 21h
mov ax, 4c00h
int 21h
int7c:
; 将ds:[si]开始的字符比较,如果是小写字母,则将其变为大写
; 因为是0结尾,这里可以用jcxz
; 小写字母的范围是 61h~7Ah,大写字母比它少20h
; 可以用 jb 61h 和 ja 7ah来做判断,并循环
push cx
push si
mov ch, 0
loop1:
mov cl, ds:[si]
jcxz loop1end
cmp cl, 61h
jb notcase
cmp cl, 7ah
ja notcase
sub cl, 20h
mov ds:[si], cl
inc si
jmp short loop1
notcase:
inc si
jmp short loop1
loop1end:
pop si
pop cx
iret
int7cend:
nop
code ends
end start
; exp1303t.asm
; 测试exp1303,用中断7ch来将ds:[si]的小写字母全部转化为大写
; 在下面用show_str显示出来
; 注意,此题用 and bytr ptr [si], 11011111b 将字符化为大写能更简化
assume cs:code
data segment
db "welcome to masm!", 0
data ends
stack segment
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0
int 7ch
mov ax, data
mov ds, ax
mov si, 0
mov dh, 2
mov dl, 3
mov cl, 2
call show_str
mov ah, 01h
int 21h
mov ax, 4c00h
int 21h
; 名称:show_str
; 功能:指定位置,用指定颜色,显示一个用0结束的字符串
; 参数:(dh) = 行号(0--24),(dl) = 列号(0--79)
; (cl) = 颜色,ds:si 指向字符串的首地址
; 返回:无
show_str:
push ax
push bx
push cx
push dx
push es
; 计算好字串开始显示的地址Y = 160*(行数-1) + 列数*2-2, B800 : Y
; 循环将参数里的字串写进显卡内存,并检测到0就返回
; bx = 160*(行数-1)
sub dh, 1h
mov al, 160
mul dh
mov bx, ax ; bx 为根据行数算出来的偏移值
; ax = 列数*2-2
mov al, 2
mul dl
sub ax, 2 ; 根据列数算出来的偏移值
add bx, ax ; 行数和列数的和存在bx中了
mov ax, 0b800h
mov es, ax
mov dl, cl ; 保存字体颜色属性
mov ch, 0
s_show_str:
mov cl, ds:[si]
mov es:[bx], cl
jcxz ok_show_str
mov es:[bx+1], dl
inc si
add bx, 2
jmp short s_show_str
ok_show_str:
pop es
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
; exp1304.asm
; 使用BIOS中断和DOS中断
assume cs:code, ds:data
data segment
db 'welcome to asm!', '$'
data ends
stack segment
stack ends
code segment
start:
; 调用BIOS中断例程
mov ah, 2
mov bh, 0
mov dh, 5
mov dl, 12
int 10h
mov ah, 9
mov al, 'a'
mov bl, 11001010b
mov bh, 0
mov cx, 3
int 10h
; 调用DOS 中断例程
mov ax, 4c00h
int 21h
code ends
end start
; exp1305.asm
assume cs:code, ds:data
data segment
db 'welcome to asm!', '$'
data ends
stack segment
stack ends
code segment
start:
mov ah, 2 ; BIOS置光标的例程
mov bh, 0 ; 第0页
mov dh, 5 ; dh 行号
mov dl, 12 ; dl 列号
int 10h
mov ax, data ;
mov ds, ax
mov dx, 0 ; ds:dx指向字符串的首地址 data:0
mov ah, 9 ; 21号中断例程的9号子程序
int 21h
mov ax, 4c00h
int 21h
code ends
end start
; exp1306.asm
; 用 int 7ch 代替loop功能,bx为偏移地址,cx为循环次数
; 安装 7ch 中断
; 关键是要在int7ch 之后,把cs:ip 的地址转为当前程序需要跳转到的cs:ip地址
; 主要注意调用中断的时候,几个重要的寄存器会压栈,顺序是:标志寄存器,cs, ip
; 这里的原理是调用中断7ch时,就把栈里的ip数值改变为循环开始地址,然后再中断返回
; 理解了以上两点,这题就没问题了,否则会访问出错,碰到操作系统的禁区
assume cs:code
code segment
start:
; 拷贝代码到0:200内存区
mov ax, cs
mov ds, ax
mov si, offset int7c
mov ax, 0
mov es, ax
mov di, 200h
mov cx, offset int7cend - offset int7c
cld
rep movsb
; 安装中断变量
mov ax, 0
mov es, ax
mov word ptr es:[7ch*4], 200h
mov word ptr es:[7ch*4 + 2], 0
mov ax, 4c00h
int 21h
int7c:
push bp
mov bp, sp
dec cx
jcxz offset int7cok
sub [bp+2], bx ; IP
int7cok:
pop bp
iret
int7cend:
nop
code ends
end start
; exp1306t
; 用 int 7ch 代替loop功能,bx为偏移地址,cx为循环次数
; 在屏幕中间显示80个 '!'
assume cs:code
code segment
start:
mov ax, 0b800h
mov es, ax
mov di, 160*12 ; 12行,刚好是80*24屏幕的中间行
mov bx, offset se - offset s
mov cx, 80
s:
mov byte ptr es:[di], '!'
mov byte ptr es:[di+1], 2
add di, 2
int 7ch
se:
nop
mov ax, 4c00h
int 21h
code ends
end start
; exp1307.asm
; 直接定址表和调用BIOS、DOS中断显示字符串
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 12,14,16,18
start:
mov ax, cs
mov ds, ax
mov bx, offset s
mov si, offset row
mov cx, 4
ok:
; BIOS置光标
mov bh, 0
mov dh, [si]
mov dl, 0
mov ah, 2
int 10h
; DOS显示字符串例程
mov dx, [bx]
mov ah, 9
int 21h
inc si ; row 是db,一个字节
add bx, 2 ; 因为dw占两个字节,所以要加2
loop ok
mov ax, 4c00h
int 21h
code ends
end start
本章深入学习到中断的一些知识,通过调试观察,能更清楚的了解到调用 int 指令和 iret 指令时 栈和各个寄存器的变化。。。