概述
第九章 转移指令的原理
8086CPU的转移行为分类:
第一种分类:
- 只修改IP---段内转移,jmp ax
- 同时修改IP和CS--段间转移。jmp 1000:0
第二种分类
- 短转移IP修改范围:-128~127
- 近转移IP修改范围:-32768~32767
转移指令分类:
- 无条件转移指令(jmp)
- 条件转移指令
- 循环指令
- 过程
- 中断
9.1 操作符offset
获取标号的偏移地址
assume cs:codesg codesg segment start: mov ax,offset start ;相当于mov ax,0 s: mov ax,offset s ;相当于mov ax,3 codesg ends end start
问题 9.1
mov ax,cs:[si]
mov cs:[di],ax
nop的机器码占一个字节
assume cs:codesg codesg segment start: mov bx,ax mov si,offset start mov di,offset s mov ax,cs:[si] mov cs:[di],ax s: nop nop mov ax,4c00h int 21h codesg ends end start
9.2 jmp指令
9.3 依据位移进行转移的jmp指令
下面jmp,jcxz类似的跳转操作的范围,都是使用补码表示。
jmp根据表示的位置是指:8位位移=标号处地址-jmp后的第一个字节的地址(也就是第一条指令)
assume cs:codesg codesg segment start: mov ax,0 jmp short s add ax,2 s: inc ax mov ax,4c00h int 21h codesg ends end start
EB03=0008-0005
assume cs:codesg codesg segment start: mov ax,0 jmp short s add ax,2 s: inc ax jmp start mov ax,4c00h int 21h codesg ends end start
EB03=0008-0005
EBF5=0000-0000B=-B(补码表示)=10001011=11110101=245=F5
jmp near ptr
段内近转移
(IP)=(IP)+16
jmp根据表示的位置是指:16位位移=标号处地址-jmp后的第一个字节的地址(也就是第一条指令)
位移范围为:-32768~32767
9.4 转移的目的地址在指令中的jmp指令
jmp far ptr
段间转移,远转移
(CS)=标号所在段的段地址;(IP)=标号在段中的偏移地址
assume cs:codesg codesg segment start: mov ax,0 mov bx,0 jmp far ptr s db 256 dup(0) s: add ax,1 inc ax mov ax,4c00h int 21h codesg ends end start
9.5 转移地址在寄存器中的jmp指令
jmp word ptr 内存单元地址(段内转移)
将IP的值设为转移地址中的值
assume cs:codesg codesg segment start: mov ax,0123h mov ds:[0],ax jmp word ptr ds:[0] mov ax,4c00h int 21h codesg ends end start
jmp dword ptr
从内存地址处开始存放两个字,高地址处是转移的目的段地址(CS),低地址处是转移的目的偏移地址。
(CS)=(内存单元地址+2)
(CS)=(内存单元地址)
assume cs:codesg codesg segment start: mov ax,0123h mov ds:[0],ax mov word ptr ds:[2],0 jmp dword ptr ds:[0] mov ax,4c00h int 21h codesg ends end start
mov word ptr ds:[2],0实际上是把一个字存放到 内存地址+2处,下面ptr再写入CS:IP
相当于
mov ax,0 mov ds:[2],ax
检测点 9.1
(1)我想的这道题就是令IP=0就行,也就是ds:[bx+1]处的值要为0
assume cs:codesg datasg segment dw 5 dup (0) datasg ends codesg segment start: mov ax,datasg mov ds,ax mov bx,0 jmp word ptr [bx+1] mov ax,4c00h int 21h codesg ends end start
(2)
这道和上面一样的思想,不过多了一个更改CS段地址,段地址可以根据datasg段来算
我们得到,DS=075AH,所以程序的地址是076AH
从已经给出的代码中,我们得到datasg段占4个字节,不满16字节(一行),但是在系统中还是占一行。
所以,我们推出程序代码的起始地址在076BH
assume cs:codesg datasg segment dd 12345678h datasg ends codesg segment start: mov ax,datasg mov ds,ax mov bx,0 add ax,1 mov [bx],bx mov [bx+2],ax jmp dword ptr ds:[0] mov ax,4c00h int 21h codesg ends end start
(3)
assume cs:codesg codesg segment start: mov ax,2000h mov es,ax mov ax,00beh ;题中是之前在2000:0就有数据,我是0000...,只能自己动手丰衣足食了。 mov es:[1000h],ax mov ax,0006h mov es:[1002h],ax jmp dword ptr es:[1000h] mov ax,4c00h int 21h codesg ends end start
9.7 jcxz指令
短转移,格式“jcxz 标号”
先判断cx,再cx自减
当cx==0时,跳转到标号处
检测点 9.2
assume cs:codesg codesg segment start: mov ax,2000h mov ds,ax mov bx,0 mov al,'b' mov ds:[bx],al mov al,'i' mov ds:[bx+1],al s: mov cl,[bx] mov ch,0 jcxz s0 inc bx loop s s0: mov dx,bx mov ax,4c00h int 21h codesg ends end start
9.8 loop指令
loop指令类似于jcxz,不过是cx!=0时,进行跳转标号处。
cx先自减,再判断
检测点 9.3
dec bx ;和inc相反,自减一
inc cx
9.9 根据位移进行转移的意义
两种,相当于绝对位置和相对位置的区别。
9.10 编译器对转移位超界的检测
实验8 分析一个奇怪的程序
可以
assume cs:codesg codesg segment mov ax,4c00h int 21h start: mov ax,0 s: nop nop mov di,offset s mov si,offset s2 mov ax,cs:[si] mov cs:[di],ax s0: jmp short s s1: mov ax,0 int 21h mov ax,0 s2: jmp short s1 nop codesg ends end start
注意红色部分的变化
在我们运行指令时,会发现运行到jmp short s之后,会运行jmp 0000,而原本应该跳到s标号处执行NOP,也就是说s处的指令发生的变化。
产生这种变化的原因,我们可以理解
mov di,offset s mov si,offset s2 mov ax,cs:[si] mov cs:[di],ax
这里实际上是将,标号s2处的指令移动到了s处,而jmp跳转地址是根据偏移地址改变的,在s处被替换的指令偏移位置,是s2处的偏移量。
s2处偏移量为18H-22H=-AH,因为jmp指令占两个内存单元空间,所以s处两个nop变成一条jmp指令,也就是从076A:000AH处,向上移动AH,也就是0,所以在跳转到s处,会显示jmp 0000,进而执行返回指令。
最后
以上就是轻松蜡烛为你收集整理的汇编学习--第八天的全部内容,希望文章能够帮你解决汇编学习--第八天所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复