《汇编语言·第三版》--王爽
将下面的程序编译、连接,用debug加载、跟踪,然后回答问题。
Table1. l51.asm
1. assume cs:code, ds:data, ss:stack 2. 3. data segment 4. dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedfh, 0cbah, 0987h 5. data ends 6. 7. 8. stack segment 9. dw 0, 0, 0, 0, 0, 0, 0, 0 10. stack ends 11. 12. 13. code segment 14. start: 15. mov ax, stack 16. mov ss, ax 17. mov sp, 16 18. 19. mov ax, data 20. mov ds, ax 21. 22. push ds:[0] 23. push ds:[2] 24. pop ds:[2] 25. pop ds:[0] 26. 27. mov ax, 4c00h 28. int 21h 29. code ends 30. 31. end start |
Figure1. l51.asm调试结果
(1) CPU执行程序,程序返回前,data段中的数据不变。
(2) CPU执行程序,程序返回前,cs =076CH、ss =076B、ds = 076A。这些值需要调试观看。
(3) 设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。
各段地址相差16的整数倍,最多相差2^16字节(64kb)。
将下面的程序编译、连接,用debug加载、跟踪,然后回答问题。
Table 2. l152.asm
1. assume cs:code, ds:data, ss:stack 2. 3. data segment 4. dw 0123H, 0456H 5. data ends 6. 7. 8. stack segment 9. dw 0, 0 10. stack ends 11. 12. 13. code segment 14. start: mov ax, stack 15. mov ss, ax 16. mov sp, 16 17. 18. mov ax, data 19. mov ds, ax 20. 21. push ds:[0] 22. push ds:[2] 23. pop ds:[2] 24. pop ds:[0] 25. 26. mov ax, 4c00h 27. int 21h 28. code ends 29. 30. end start |
Figure2. 152.asm调试结果
(1) CPU执行程序,程序返回前,data段中的数据不变。
(2) CPU执行程序,程序返回前,cs =076CH、ss =076B、ds =076A。这些值需要调试观看。
(3) 设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。
Figure3. stack:14和stack:12处被写入的内容
运行到把data段的数据压倒栈中的地方,此时stack:14和stack:12处显示压入的值。单步运行:
每当执行一个pop指令后,出栈后的内存单元内的数据就发生了变化,它不保证经出栈后的内存单元的值还保持原值。
(4) 对于如下定义的段:
段名 segment
…
段名 ends
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为N字节(N为16的正整数倍),(N/16 + 1) * 16(N/16取商的整数部分,如17/16 = 1)字节(不超过64KB)。将下面的程序编译、连接,用debug加载、跟踪,然后回答问题。
Table 3. l53.asm
1. assume cs:code, ds:data, ss:stack 2. 3. code segment 4. start: mov ax, stack 5. mov ss, ax 6. mov sp, 16 7. 8. mov ax, data 9. mov ds, ax 10. 11. push ds:[0] 12. push ds:[2] 13. pop ds:[2] 14. pop ds:[0] 15. 16. mov ax, 4c00h 17. int 21h 18. code ends 19. 20. 21. data segment 22. dw 0123h, 0456h 23. data ends 24. 25. 26. stack segment 27. dw 0, 0 28. stack ends 29. 30. end start |
Figure5. 各段地址
(1) CPU执行程序,程序返回前,data段中的数据不变。
(2) CPU执行程序,程序返回前,cs =076AH、ss =076E、ds =076D。这些值需要调试观看。
(3) 设程序加载后,code段的段地址为X,则data段的段地址为X+3,stack段的段地址为X+4。
如果将1、2、3题中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
Figure6. 无start end语句的汇编程序
这些莫名的指令都来源于data段的数据。
所以,去掉“start”后,3中的汇编程序可以正常运行。
Table 4. l55.asm
1. assume cs:code 2. 3. a segment 4. db 1, 2, 3, 4, 5, 6, 7, 8 5. a ends 6. 7. 8. b segment 9. db 1, 2, 3, 4, 5, 6, 7, 8 10. b ends 11. 12. 13. c segment 14. db 0, 0, 0, 0, 0, 0, 0, 0 15. c ends 16. 17. 18. code segment 19. start: mov ax, a 20. mov ds, ax 21. mov ax, b 22. mov es, ax ;es作为b数据段段地址 23. mov ax, c 24. mov ss, ax ;ss作为c数据段段地址 25. 26. mov bx, 0 27. mov cx, 8 28. s: mov al, [bx] 29. add al, es:[bx] 30. mov ss:[bx], al 31. inc bx 32. loop s 33. 34. mov ax, 4c00h 35. int 21h 36. code ends 37. end start |
用masm编译连接以上程序生成l55.exe。用debug加载l55.exe,首先用u命令查到c数据段的段地址076CH,然后找到“int 21h”地址,运行至“int 21h”处后用d 076c:0 8命令查看c数据段内容是否对应为a,b两数据段数据对应相加的值。
Table 5. l156.asm
1. assume cs:code 2. 3. a segment 4. dw 1, 2, 3, 4, 5, 6, 7, 8, 9, 0ah, 0bh, 0ch, 0dh, 0eh, 0fh, 0ffh 5. a ends 6. 7. 8. b segment 9. dw 0, 0, 0, 0, 0, 0, 0, 0 10. b ends 11. 12. 13. code segment 14. start: mov ax, a 15. mov ds, ax 16. 17. mov ax, b 18. mov ss, ax 19. mov sp, 16 20. 21. mov bx, 0 22. mov cx, 8 23. s: push [bx] 24. inc bx 25. inc bx 26. loop s 27. 28. mov ax, 4c00h 29. int 21h 30. code ends 31. end start |
汇编源程序中,用“end start”说明程序的入口地址为“start”处,这个入口地址将被写入可执行文件的描述信息,可执行文件被加载入内存后,CPU的CS:IP被设置指向这个入口地址,从而开始执行程序中的第一条指令。标号“start”在“code”段中,这样CPU段中的内容就被当作指令来执行了。再在代码段中设置ss指向某段,那么这段就可以被当成栈来使用(使用push, pop指令时,ss和sp两个寄存器会自动配合),数据段同理。CPU是如何处理我们定义的段中的内容,是当作指令执行,还是当作数据访问,还是当作栈空间,完全依靠程序中的汇编指令,和汇编指令对CS:IP、SS:SP、DS等寄存器的设置决定的。
汇编源程序中的段被加载到内存中时,以(16)字节对齐的方式连续存储。