0x10:源程序
标号:就是xxx segment和xxx ends定义的段中的xxx,它就是段名,最终将处理为一个段的段地址。
程序返回:
1 | mov ax, 4c00H |
在第一个程序中的这两条指令实现程序返回。
程序的编译、连接和执行:
编写一个test.asm
文件,
编译:masm test.asm
,连接:link test.obj
,执行:test.exe
。
简化编译、连接过程:在每条编译、连接命令之后加上分号。
0x11:程序执行过程跟踪
通过debug工具来跟踪 test.exe 程序的执行过程:
发现 CS:IP 指向程序的入口,CX 寄存器存放程序的长度,也就是机器码(汇编指令转成机器码)的长度。
为什么DS的内容比CS少10H?
这涉及到DOS系统中 .EXE 文件中的程序的加载过程:
程序加载后,ds 存放程序所在内存的段地址,也就是PSP的段地址。
由于PSP占据了10H的内存,所以程序的物理地址是 [ds]+10H:0,这个段地址就是 cs 的内容。
用u
命令可以将机器指令都翻译成汇编指令。
然后用t
命令单步执行。注意到int 21
时,要用p
命令执行!
用q
命令退出debug。
0x12:[bx] 和loop 指令
[bx]
的含义:[bx](和[0]类似)同样表示一个内存单元,它的偏移地址在bx中,段地址默认在ds中。
loop
指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作,
- (cx) = (cx) - 1; cx 存放loop循环的循环次数
- 判断 cx 中的值,不为零则转至标号处执行程序,如果为零则向下执行。
定义一个描述性的符号:“()”,它用来表示一个寄存器或一个内存单元的内容。
约定用符号 idata 表示一个常量,如:mov ax,[idata]
表示将 ds:idata 处的数据送入 ax寄存器。
计算2^12:
1 | assume cs:code |
debug的g
命令,如g 0016
,将从 cs:ip 位置执行指令到 cs:0016 位置。
不用一步步单步执行了。
0x13:debug 和汇编编译器 masm 对指令的不同处理
0x14:[bx] 和loop 指令的联合应用
计算 ffff:0~ffff:b 单元中数据的和,结果存储在 dx 中。
注意:每个单元中存放的是8位数据,而 dx 是一个16位寄存器,需要将 ah 置零,将 al 放8位数据,二者拼起来就是一个16位数据。
解释:inc bx
就是将 bx 中的内容自增1。
0x15:段前缀
1 | mov ax, ds:[bx] |
这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:”,“cs:”,“ss:”,“es:”,在汇编语言中称为段前缀。
将内存ffff:0 ~ ffff:b
单元中的数据复制到0:200 ~ 0:20b
单元中。
1 | assume cs:code |