王爽《汇编语言》第十三章所有练习解答

时间:2022-09-08 01:29:54

 请注意,里面有程序和测试程序,例如 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 指令时 栈和各个寄存器的变化。。。