《汇编语言·第三版》--王爽
1 分析一个奇怪的程序
1. assume cs:codesg 2. 3. codesg segment 4. mov ax, 4c00h 5. int 21h 6. 7. start: mov ax, 0 8. 9. s: nop 10. nop 11. 12. mov di, offset s 13. mov si, offset s2 14. mov ax, cs:[si] 15. mov cs:[di], ax 16. 17. s0: jmp short s 18. 19. s1: mov ax, 0 20. int 21h 21. mov ax, 0 22. 23. s2: jmp short s1 24. nop 25. codesg ends 26. end start |
(1) 分析上面的程序,在运行前思考:这个程序可以正确返回吗?
答:不能。因为程序运行过程为s --> s0 --> s1 --> s2 --> s1 --> s2 --> s1……
(2) 运行后思考:为什么是这种结果?
答:运行程序后发现程序可以正确返回。再读程序并思之。原来程序运行的过程为:7 --> 17,再是3 --> 5,此时程序退出。数字为下表程序的行号。为什么是这样呢?因为12 ~ 15行代码将“23行的指令(机器码)拷贝到了9行处”,23行处的机器码的偏移量为s2 – s1,刚好等于s – codesg。故而,当程序跳转到s处运行s处指令时,程序将会从codesg处运行,故而程序可以正确返回。
2 根据材料编程
(1) 要求
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串’welcome to masm!’。
编程所需的知识通过阅读、分析下面的材料获得。
80 x 25彩色字符模式显示缓冲区(以下简称为显示缓冲区)的结构:
内存地址空间中,B8000H ~ BFFFFH共32KB的空间,为80 x 25彩色字符模式的显示缓冲区。向这个地址空间写入数据,写入的内容将立即出现在显示器上。
在80 x 25彩色字符模式下,显示器可显示25行,每行80个字符,每个字符可以有256种属性(背景色、前景色、闪烁、高亮等组合信息)。
这样,一个字符在显示缓冲区中就要占两个字节,分别存放字符的ASCII码和属性。80 x 25模式下,一屏的内容在显示缓冲区中共占4000个字节。
显示缓冲区分为8页,每页4KB[12位偏移](约等于4000B),显示器可以显示任意一页的内容。一般情况下,显示第0页的内容。也就是说通常情况下,B8000H ~ B8F9FH中的4000个字节的内容将出现在显示器上。
在一页显示缓冲区中:
偏移000 ~ 09F对应显示器上的第1行(80个字符占160个字节);
偏移0A0 ~13F对应显示器上的第2行;
偏移140 ~ 1DF对应显示器上的第三行;
依次类推,可知,偏移F00 ~ F9F对应显示器上的第25行。[这个跟内存的真实结构没关系,是内存到屏幕坐标的一个对应关系]
在一行中,一个字符占两个字节的存储空间(一个字),低位字节存储字符的ASCII码,高位字节存储字符的属性。一行共有80个字符,占160个字节。
即在一行中:
00 ~ 01单元对应显示器上的第一列;
02 ~ 03单元对应显示器上的第2列;
04 ~ 05单元对应显示器上的第3列;
依次类推,可知,9E ~ 9F单元对应显示器上的第80列。
例:在显示器的0行0列显示黑底绿色的字符串’ABCDEF’(’A’的ASCII码值为41H,02H表示黑底绿色)
显示缓冲区里的内容为:
【】【】【】【 00 01 02 03 04 05 06 07 08 09 0A 0B … 0E 0F
B800:0000 41 02 42 02 43 02 44 02 45 02 46 02 … .. ..
..
..
B800:00A0 .. .. .. .. .. .. .. .. .. .. .. .. … .. ..
可以看出,在显示缓冲区中,偶地址存放字符,奇地址存放字符的颜色属性。
一个在屏幕上显示的字符,具有前景(字符色)和背景(底色)两种颜色,字符还可以以高亮度和闪烁的方式显示。前景色、背景色、山所、高亮等信息都被记录在属性字节中。
属性字节的格式:
【】【】【7 6 5 4 3 2 1 0
含义 BL R G B I R G B
R:红色,G:绿色,B:蓝色
[绿色字属性字节内容:02H,绿底红色字属性字节内容:00100100b, 24H,白底蓝色字属性字节内容:0111 0001b, 71H]
可以按位设置属性字节,从而配出各种不同的前景色和背景色。
比如:
红底绿字,属性字节为:01000010B;
红底闪烁绿字,属性字节为:11000010B
红底高亮绿字,属性字节为:01001010B
黑底白字,属性字节为:00000111B
白底蓝字,属性字节为:01110001B
例:在显示器的0行0列显示红底高亮闪烁绿色的字符串’ABCDEF’(红底高亮闪烁绿色,属性字节为:11001010B,CAH)
显示缓冲区里的内容为:
【】【】【】【 00 01 02 03 04 05 06 07 08 09 0A 0B … 9E 9F
B800:0000 41 CA 42 CA 43 CA 44 CA 45 CA 46 CA … .. ..
..
B800:00A0 .. .. .. .. .. .. .. .. .. .. .. .. … .. ..
注意,闪烁效果必须在全屏DOS方式下才能看到。
(2) 分析
编程要求在屏幕中间显示’welcome to masm!’字符串,加上空格共16个字符。屏幕为80 x 25(默认显示第0页内容)。16个字符在一行中会占用32个字节,那么字符串从第12、13、14行第33列处开始写。各行对应的内存地址分别为(偶地址开始存字符):
【】【】【 B800:6E0 + 72
B800:780+ 72
B800:820+ 72
(3) 程序
1. ;ds段寄存器指向'welcome to masm!'数据段 2. ;es段寄存器指向显存地址,使用[bp+ si]的方式防显存 3. ;bp为第12行偏移地址,每次加160 4. assume cs:codesg, ds:datasg 5. 6. datasg segment 7. db 'welcome to masm!' 8. datasg ends 9. 10. 11. codesg segment 12. start: 13. mov ax, datasg 14. mov ds, ax 15. mov bx, 0 16. 17. mov ax, 0b800h 18. mov es, ax 19. mov bp, 6e0h ;屏幕12行对应的显存偏移地址 20. mov si, 0 ;作为显存地址递增作用 21. 22. 23. mov cx, 16 24. s0: 25. mov al, [bx] 26. mov es:[bp + si + 72],al ;字符 27. inc si 28. mov byte ptr es:[bp +si + 72], 02h ;字符前景色 29. inc si 30. inc bx 31. loop s0 32. 33. 34. mov si, 0 35. mov bx, 0 36. add bp, 160 37. mov cx, 16 38. s1: 39. mov al, [bx] 40. mov es:[bp + si + 72],al ;字符 41. inc si 42. mov byte ptr es:[bp +si + 72], 24h ;字符前景色 43. inc si 44. inc bx 45. loop s1 46. 47. mov si, 0 48. mov bx, 0 49. add bp, 160 50. mov cx, 16 51. s2: 52. mov al, [bx] 53. mov es:[bp + si + 72],al ;字符 54. inc si 55. mov byte ptr es:[bp +si + 72], 71h ;字符前景色 56. inc si 57. inc bx 58. loop s2 59. 60. mov ax, 4c00h 61. int 21h 62. codesg ends 63. end start |
(4) 运行
用masm编译源程序:masm src\...\l9
用连接器连接目标文件:link src\...\l9
最后在dos下运行可执行程序:src\...\l9.exe得到以下运行结果