《汇编语言(第四版)》 . 王爽著 . 清华大学出版社 . 2019
¶实验 8 分析一个奇怪的程序
可以修改 IP,或同时修改 CS 和 IP 的指令统称为转移指令
8086CPU 的转移行为:
段内转移:只修改 IP
段间转移:同时修改 CS 和 IP
由于转移指令对 IP 的修改范围不同,段内转移又分为:短转移和(80 ~ 7F)近转移(8000 ~ 7FFF)
依据位移进行转移的 jmp 指令
1 | jmp short 标号 ;段内短转移 (IP)=(IP)+8 位位移 |
转移的目的指令在指令中的 jmp 指令
1 | jmp far ptr 标号 ;段间转移 / 远转移 |
8086CPU 的转移指令分为:
无条件转移指令
条件转移指令
循环指令
过程
中断
¶检测点 9.1
1 | jmp word ptr 内存单元地址 ;段内转移 |
1 | cs:code |
段内转移,CS:IP
要指向程序的第一条指令,则目的偏移地址为 0 即可
1 | cs:code |
段间转移,内存单元高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址
CS=0006H, IP=00BEH
¶检测点 9.2
1 | jcxz 标号 ;if((cx)==0) jmp short 标号; |
1 | cs:code |
这里能否将补全的前两句指令替换成 mov cx,ds:[bx]
,它们之间的区别是什么?
题目要求在内存 2000H 段中查找第一个值为 0 的字节,而 cx 中存放的是字,直接传送是字操作,因此不能直接传送到 cx 中去,应该传送字节给 cx 的低 8 位 cl,再给其高 8 位 ch 赋 0
¶检测点 9.3
1 | loop 标号 |
1 | cs:code |
loop 指令先要执行 (cx)=(cx)-1
再判断 cx 是否为 0,所以应该先对 cx 加 1
¶实验任务
分析下面的程序,在运行前思考:这个程序可以正确返回吗?
运行后思考:为什么会是这种结果?
通过这个程序加深对相关内容的理解。
1 | cs:codesg |
这个程序可以正确返回
程序读上去的确非常奇怪,但是其中蕴含着一个简单而又深刻的原理,那就是此处 CPU 在执行 jmp 指令时并不需要转移的目标地址
我们来看程序
1 | mov ax,cs:[si] |
执行完这两句指令后,我们可能会错误地以为,cs:[si]
处的指令 jmp short s1
通过 ax 寄存器传送到了 cs:[di]
处,即标号 s 处,然后接下来程序转移到标号 s 处,再转移到标号 s1 处,似乎程序无法正确返回
而实际上,通过 ax 转移的不是 jmp short s1
这句指令,而是这句指令的编译后的机器码,我们用 Debug 跟踪可知,编译后的机器码为 EBF6
,其中 EB 代表 jmp 指令,F6 则不是转移的目标地址,而是要转移的位移
这个位移我们显然是可以计算出来的,回忆一下 CPU 执行指令的过程:
1)从 CS:IP
指向内存单元读取指令,读取的指令进入指令缓冲器
2)(IP)=(IP)+所读取指令的长度,从而指向下一条指令
3)执行指令,转到 1),重复这个过程
1 | s1: mov ax,0 ;B80000 |
所以这个位移不是标号 s2 到标号 s1 的差值,而是 jmp short s1
后一条指令的地址与标号 s1 的差值,这个差值即为中间指令机器码的长度(包括 jmp short s1
的长度),此处为 10 个字节,又因为是向低地址方向转移,所以位移为 -10,它的二进制补码即为 F6
知道这点后,我们就明白,当程序跳转到标号 s 处时,CPU 读取程序复制过来的内容,然后使 (IP)=(IP)+2,然后执行向低地址方向作 10 个字节的位移(短转移),此时 CS:IP
指向 mov ax,4c00h
,于是程序得以正确返回
补充材料:《深入理解计算机系统》
3.6.4 跳转指令的编码
在汇编代码中,跳转目标用符号标号书写。汇编器,以及后来的链接器,会产生跳转目标的适当编码。跳转指令有几种不同的编码,但是最常用都是 PC 相对的(PC-relative)。也就是,它们会将目标指令的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。这些地址偏移量可以编码为 1、2 或 4 个字节。第二种编码方法是给出“绝对”地址,用 4 个字节直接指定目标。汇编器和链接器会选择适当的跳转目的编码。
更深入的:7.7.2 重定位符号引用
¶汇编语言实验合集
实验 1 查看 CPU 和内存,用机器指令和汇编指令编程
实验 2 用机器指令和汇编指令编程
实验 3 编程、编译、连接、跟踪
实验 4 [bx] 和 loop 的使用
实验 5 编写、调试具有多个段的程序
实验 6 实践课程中的程序
实验 7 寻址方式在结构化数据访问中的应用
实验 8 分析一个奇怪的程序
实验 9 根据材料编程
实验 10 编写子程序
课程设计 1
实验 11 编写子程序
实验 12 编写 0 号中断的处理程序
实验 13 编写、应用中断例程
实验 14 访问 CMOS RAM
实验 15 安装新的 int9 中断例程
实验 16 编写包含多个功能子程序的中断例程
实验 17 编写包含多个功能子程序的中断例程
课程设计 2