可以修改IP,或者同时修改cs和ip的指令统称为转移指令。
8086cpu的转移行为有以下几类:
- 只修改ip,称为段内转移,如
jmp ax
- 同时修改cs和ip,称为段间转移,如
jmp 1000:0
根据转移指令对于ip的修改范围不同,所以段内转移又分为:短转移和近转移
- 短转移IP的修改返回为-128~127
- 近转移IP的修改范围为-32768~32767
8086cpu的转移指令分为以下几类:
- 无条件转移指令(如:jmp)
- 条件转移指令 (jcxz)
- 循环指令(loop)
- 过程
- 中断
不同转移指令的转移条件可能不同,但是转移的基本原理是相同的
操作符offset
offset是在汇编语言中是由编译器处理的符号,功能为取得标号的偏移地址。也就是相对于代码段的偏移地址,就是直接IP值了。
jmp指令
jmp为无条件转移指令,可以只修改IP,也可以同时修改cs和ip。
jmp指令需要给出两种信息:
- 转移的目的地址
- 转移的距离(段间转移,段内短转移,段内近转移)
不同的给出目的地址的方法不同,和不同的转移位置,对应有不同格式的jmp指令。
依据位移进行转移的jmp指令
jmp short 标号
(IP)=(IP)+8位位移
这种格式的jmp指令实现的是段内短转移。对ip的修改范围限定为-128~127之间,可以看出正好是一个字节能够表示的范围。jmp near ptr 标号
(IP)=(IP)+16位位移
于jmp short
功能相同,只不过他实现的是段内近转移。简单来说就是转移的距离拉长(虽然仍然是在段内)
小贴士:
可以看到jmp short
与jmp near ptr
(段内转移)并没有直接将转移的目的地址直接写入机器指令中。而是将一个相对偏移地址写入了机器指令。(但是debug在对应的汇编指令中会看到偏移地址)
具体来说就是将标号地址相对于jmp指令的下一条指令的地址写入了机器指令。
也就是说,cpu在执行jmp指令的时候并不需要转移的目标地址。
转移的目的地址在指令中的jmp指令
前面讲到的段内转移指令其机器指令中并没有转移的目的地址,而是相对于当前ip的转移位移。
jmp far ptr 标号
实现段间转移,又称为远转移。
(CS)=标号所在段的段地址;(IP)=标号在段中的偏移地址
far ptr
将标号的地址写入了汇编指令。
jmp指令的机器码为EA,可以很明显的看出来,其中高地址放段地址,低地址放偏移地址。
顺便说明,像是jmp 1000:0
是在debug中使用的,在汇编代码中并不能使用这样的指令。
转移地址在寄存器中的jmp指令
指令格式: jmp 16位reg
功能: (IP)=(16位reg)
转移地址在内存中的jmp指令
转移地址在内存中的jmp指令有两种格式:
jmp word ptr 内存单元地址
(段内转移)
更改ip值。jmp dword ptr 内存单元地址
(段间转移)
目标内存中放着两个字,其中高地址处的字为转移目标的段地址,低地址处的字为转移的目标的段偏移地址。
(CS)=(内存单元地址+2)
(IP)=(内存单元地址)
jcxz指令
jcxz
为条件转移指令。所有的条件转移指令都是短转移指令,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围为-128~127.
功能:当cx寄存器的值为0是执行转移,否则什么也不做。
loop指令
loop指令为循环指令,所有的循环指令都是短转移。
根据位移进行转移的意义
高端大气的说法就是方便了程序段在内存中的浮动装配。
实际上就是无所谓程序在内存中的地址,程序中的转移指令无需改变。
编译器对于转移位移超界的检测
根据位移进行转移的指令,他们的转移范围收到转移位移的限制,如果在源程序中出现了转移范围超界的问题,在编译的时候,编译器将会报错。
分析一个奇怪的程序
就是一个计算通过相对偏移位置计算偏移位置的问题。
会注意到在执行完mov cs:[di], ax
以后,s段的9090
(nop nop)变成了EBF6
(值为F6EB【小端序】)。同时想到的是同样都是EBF6
却翻译出了不同的汇编指令。然而实际上都是相同的,翻译的问题是编译器做的。他将机器码翻译了以下,也就是将相对偏移地址直接翻译成为了IP中的偏移地址。
即使上面讲到过的偏移地址=jmp的下一条指令地址+相对偏移地址(注意到F6的问题,计算机中的数据以补码方式存储)。他就是将偏移地址算了出来。
根据材料编程
答案:
assume cs:code, ds:data
data segment
db 'welcome to masm!' ; 文字
db 00000010B, 00100100B, 01110001B ; 属性
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, 0b800H
mov es, ax
mov bx, 0
mov si, 0
mov di, 64
mov bp, 6e0H
mov cx, 3
ln:
mov dx, cx
mov cx, 16
mov bx, 0
mov di, 64
s:
mov al, [bx]
mov ah, 16[si]
mov es:[bp].[di], ax
inc bx
add di, 2
loop s
add si, 1
add bp, 160
mov cx, dx
loop ln
mov ax, 4c00H
int 21H
code ends
end start
注意数值不能以字母开头