《汇编语言·第三版》--王爽
1 显示字符串
(1) 问题
编写安装int 7ch中断例程,功能为显示一个用0结束的字符串,中断例程安装在0:200处。
参数:(dh) = 行号,(dl) = 列号,(cl) = 颜色,ds:si指向字符串首地址。
以上中断例程安装成功后,对下面的程序进行单步跟踪,尤其注意观察int、iret指令执行前后CS、IP和栈中的状态。
Table 1. l131t.asm
1. assume cs:code 2. 3. data segment 4. db "welcome to masm! ", 0 5. data ends 6. 7. code segment 8. start: mov dh,10 9. mov dl,10 10. mov cl,2 11. mov ax,data 12. mov ds,ax 13. mov si,0 14. int 7ch 15. 16. mov ax,4c00h 17. int 21h 18. code ends 19. end start |
(2) 安装代码
编写符合显示字符串的中断例程,只需要将课程设计I中显示字符串的show_str子函数(call – retf换成int - iret)安装到0:200处,再设置中断向量表即可。
1. assume cs:codesg 2. 3. 4. codesg segment 5. start: 6. mov ax, cs 7. mov ds, axg 8. mov si, offset show_str ;用ds:[si]指向需要被复制的程序 9. 10. mov ax, 0 11. mov es, ax 12. mov di, 200h ;中断例程内存段 13. 14. mov cx, offset str_e - offset show_str 15. cld 16. rep movsb ;使用串传送指令,从ds:[si]传送cx字节到es:[di] 17. 18. mov ax, 0 19. mov es, ax 20. mov word ptr es:[7ch *4], 200h 21. mov word ptr es:[7ch *4 + 2], 0 22. ;设置中断向量表,N号中断的中断程序入口地址保存在(N * 4 + 2):(N * 4)内存中 23. 24. nop 25. mov ax, 4c00h 26. int 21h 27. 28. ;功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串 29. ;参数:(dh) = 行号(取值范围 0 ~ 24),(dl) = 列号(取值范围0 ~ 79),(cl) = 颜色,ds:si指向字符串的首地址 30. ;返回:无 31. show_str: 32. push ax 33. push cx 34. push dx 35. push es 36. push bp 37. push di 38. push si 39. 40. mov ax, 0b800h 41. mov es, ax ;es段保存显存段地址 42. 43. mov al, cl ;字符前景色保存到al 44. 45. mov bp, 0 46. mov ch, 0 47. mov cl, dh 48. inc cl 49. str_s0: 50. jcxz str_s1 51. add bp,160 ;行号对应的显存地址 52. loop str_s0 53. str_s1: 54. mov di,0 55. mov ch,0 56. mov cl,dl 57. str_s2: 58. jcxz str_s3 59. add di,2 ;列号对应的显存地址 60. loop str_s2 ;es:[di + bp]为dh行dl列对应的显存地址 61. 62. str_s3: 63. mov cl,ds:[si] 64. jcxz str_s4 ;检测当前字符是否为0,如果为0则转移到s4处执行 65. mov es:[bp+ di],cl 66. inc di 67. mov es:[bp+di], al ;字符前景色 68. inc di 69. inc si 70. loop str_s3 71. 72. str_s4: 73. pop si 74. pop di 75. pop bp 76. pop es 77. pop dx 78. pop cx 79. pop ax 80. iret 81. str_e: nop 82. codesg ends 83. end start |
(3) 调试
将l131t.asm和l131i.asm分别编译连接为l131t.exe和l131i.exe,因为0:200 ~ 0:3FF内存操作系统不会占用(回收),所以运行l131i.exe程序后,显示字符串的程序依然在内存中,此时再运行l131t.exe可得如下结果:
2 完成loop指令功能
(1) 问题
编写并安装int 7ch中断例程,功能为完成loop指令的功能。
参数:(cx) = 循环次数,(bx) = 位移。
以上中断例程安装成功后,对下面的程序进行单步跟踪,尤其注意观察int、iret指令执行前后CS、IP和栈中的状态。
在屏幕中间显示80个“!”。
Table3. l132t.asm
1. assume cs:code 2. 3. code se gment 4. start: mov ax, 0b800h 5. mov es, ax 6. mov di, 160 * 12 7. mov bx, offset s -offset se 8. mov cx, 80 9. s: 10. mov byteptr es:[di], '!' 11. add di, 2 12. int 7ch 13. se: nop 14. 15. mov ax, 4c00h 16. int 21h 17. code ends 18. end start |
(2) 安装代码
1. assume cs:codesg 2. 3. 4. codesg segment 5. start: 6. mov ax, cs 7. mov ds, ax 8. mov si, offset lp ;用ds:[si]指向需要被复制的程序 9. 10. mov ax, 0 11. mov es, ax 12. mov di, 200h ;中断例程内存段 13. 14. mov cx, offset lp_e -offset lp 15. cld 16. rep movsb ;使用串传送指令,从ds:[si]传送cx字节到es:[di] 17. 18. mov ax, 0 19. mov es, ax 20. mov word ptr es:[7ch *4], 200h 21. mov word ptr es:[7ch *4 + 2], 0 22. ;设置中断向量表,N号中断的中断程序入口地址保存在(N * 4 + 2):(N * 4)内存中 23. 24. nop 25. mov ax, 4c00h 26. int 21h 27. 28. ;功能:实现loop的功能 29. ;参数:(cx) = 循环次数,(bx) = 位移 30. ;返回:无 31. lp: 32. push bp 33. mov bp, sp 34. dec cx 35. jcxz lpret 36. add [bp +2], bx 37. lpret: pop bp 38. iret 39. 40. lp_e: nop 41. codesg ends 42. end start |
(3) 调试
Figure4. 实现loop指令中断例程运行结果
int、iret执行前后CS、IP和栈内容变化与1相似。
3 补全程序,显示英文诗
(1) 问题
下面的程序,分别在屏幕的2、4、6、8行显示4句英文诗,补全程序。完成编译运行后,体会其中的编程思想。
1. assume cs:codesg 2. 3. codesg segment 4. s1: db 'Good, better, best,', '$' 5. s2: db 'Never let it rest,', '$' 6. s3: db 'Till good is better,', '$' 7. s4: db 'And better, best. ','$' 8. s: dw offset s1, offsets2, offset s3, offset s4 9. row: db 2, 4, 6, 8 10. 11. start: 12. mov ax, cs 13. mov ds, ax 14. mov bx, offset s 15. mov si, offset row 16. mov cx, 4 17. 18. ok: 19. mov bh, 0 20. mov dh, ds:[si] 21. mov dl, 0 22. mov ah, 2 23. int 10h ;置光标 24. 25. mov dx,ds:[bx] 26. mov ah, 9 27. int 21h ;显示以ds:[dx]首地址以'$'结尾的字符串 28. 29. inc si 30. add bx, 2 31. loop ok 32. 33. mov ax, 4c00h 34. int 21h 35. codesg ends 36. end start |
绿色下划线处为填补的程序。将多个字符串的地址组织在一块,通过寻址其地址来显示实现C中数组一样的功能。
(3) 调试
回车一片后再运行经编译和连接的程序,结果如下:
Figure5. 运行结果
此时光标在红色方框内,不用检查自己是否写了死循环程序。