汇编学习--第八天

第九章 转移指令的原理

8086CPU的转移行为分类:

第一种分类:

  1. 只修改IP---段内转移,jmp ax
  2. 同时修改IP和CS--段间转移。jmp 1000:0

 

第二种分类

  1. 短转移IP修改范围:-128~127
  2. 近转移IP修改范围:-32768~32767

 

转移指令分类:

  1. 无条件转移指令(jmp)
  2. 条件转移指令
  3. 循环指令
  4. 过程
  5. 中断

 

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,进而执行返回指令。

 

posted @ 2019-07-08 21:51  Hk_Mayfly  阅读(565)  评论(0编辑  收藏  举报