8086汇编#9

第九章 转移指令的原理 – 汇编语言提纲

第九章 转移指令的原理

第九章 转移指令的原理

9.0 绪论

1.可以修改IP。或者同时修改CS和IP的指令统称为转移指令

2.转移的分类

·只修改IP时,叫做段内转移

·同时修改CS和IP,叫做段间转移

2. 段内转移分为:

·短转移:IP的修改范围为-128~127

·近转移:IP的修改范围为-32768~32767

3.8086转移指令的分类

·无条件转移指令(如:jmp)

·条件转移指令

·循环指令(如loop)

·过程

·中断

9.1操作符offset

1. 功能:由编译器处理,取得标号的偏移地址
2. 用法:offset 标号

问题9.1

有如下的程序段,添加两条指令,使得运行中该程序将s处的一条指令复制到s0处

Program 9-Problem-1
assume cs:coding
codesg segment
s:mov ax,bx
mov si,offset s
mov di,offset s0
______________
______________
s0:nop
nop
codesg ends
end
注:nop的机器码占一个字节,此处为占位作用。答案:
mov cx,cs;[si]
mov cs:[di],cx

9.2~9.6 jmp指令

1.jmp为无条件转移指令,可以只修改IP,也可以同时修改CS和IP

2.jmp指令要给出的两条信息:

(1)转移的目的地址

(2)转移的距离(段间转移,段内短转移,段内近转移)

3.依据位移进行转移的jmp指令

·jmp short 标号(转到标号处执行指令)

该格式的指令进行段内短转移,对IP的修改范围为-128~127,即向前转移最多越过128个字节,向后转移最多可以越过127个字节

在debug下显示为jmp xxxx,但机器码中不包含转移的目的地址,因为CPU在执行jmp指令时不需要目的地址,而需要位移。

功能:(IP)=(IP)+8位位移

(1)8位位移=标号处的地址-jmp指令后的第一个字节的地址

(2) short指名为8位位移
(3) 位移用补码表示
(4) 位移在编译时算出
·jmp near ptr 标号

该指令实现段内近转移,与jmp short 标号 相似,但为16位位移,范围为-32768~32767

4.转移的目的地址在指令中的jmp指令

·jmp far ptr 标号

实现段间转移(远转移),功能:(CS)=标号所在的段地址 (IP)=标号所在段的偏移地址

标号指明了段地址和偏移地址

在debug中显示为jmp xxxx:xxxx

5. 转移指令在寄存器中
·jmp 16位reg

功能 (IP)=(16位reg)

6. 转移地址在内存中的jmp指令
·jmp word ptr 内存单元地址(段内转移)

功能:从内存单元地址处取出一个字,作为转移的目的地址

·jmp dword ptr 内存单元地址(段间转移)

功能:从内存单元中取出两个字,高地址处的字是转移的目的段地址,低地址处为转移的目的偏移地址。即:

(CS)=(内存单元地址+2)

(IP)=(内存单元地址)

检测点9.1

(1)程序如下。

assume cs:code
data segment
   dw 2 dup (0)
data ends
code segment
  start: mov ax,dtat
         mov ds,ax
         mov bx,0
         jmp word ptr [bx+1]
code ends
end start

若要使jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?

答案①db 3 dup (0)
答案②dw 2 dup (0)

答案③dd 0

jmp word ptr [bx+1]为段内转移,要CS:IP指向程序的第一条指令,应设置ds:[bx+1]的字单元(2个字节)存放数据应为0,则(ip)=ds:[bx+1]=0

简单来说就是,只要ds:[bx+1]起始地址的两个字节为0就可以了

(2)程序如下。

assume cs:code
data segment
   dd 12345678h
data ends
code segment
  start: mov ax,data
         mov ds,ax
         mov bx,0
         mov [bx],  bx    ;或mov [bx], word ptr 0 ;或mov [bx], offset start 
         mov [bx+2],  cs  ;或mov [bx+2],  cs      ;或mov [bx+2], seg code   
         jmp dword ptr ds:[0]
code ends
end start

补全程序,使用jmp指令执行后,CS:IP指向程序的第一条指令。

第一格可填①mov [bx],bx②mov [bx],word ptr 0③mov [bx],offset start等。

第二格可填①mov [bx+2],cs②mov [bx+2],cs③mov [bx+2],seg code等。

解析:
jmp dword ptr ds:[0]为段间转移,(cs)=(内存单元地址+2),(ip)=(内存单元地址),要CS:IP指向程序的第一条指令,第一条程序地址cs:0,应设置CS:IP指向cs:0 

程序中的mov [bx],bx这条指令,是将ip设置为0

mov [bx+2],cs,将cs这个段地址放入内存单元  

执行后,cs应该不变,只调整ip为0,(ip)=ds:[0]=0

(3)用Debug查看内存,结果如下:

2000:1000 BE 00 06 00 00 00 ......

则此时,CPU执行指令:

mov ax,2000h
mov es,ax
jmp dword ptr es:[1000h]

后,(cs)= 0006H ,(ip)= 00BEH

解析:
jmp dword ptr为段间转移,高位存放段地址,低位存放偏移地址

(cs)=(内存单元地址+2),(ip)=(内存单元地址)

根据书P16,对于寄存器AX,AH为高位(前1字节为高位),AL为低位(后1字节为低位)

推算出(内存单元地址)=00beh,(内存单元地址+2)=0006h

根据书P182,高位存放段地址(后2个字节为高位),低位存放偏移地址(前2个字节为低位)

(cs)=(内存单元地址+2),(ip)=(内存单元地址)

推算出(cs)=0006h,(ip)=00beh

9.7 jcxz指令

1.jcxz指令为有条件转移指令,所有的有条件转移指令都是短转移。在对应的机器码中包含转移的位移

2.格式:jcxz 标号(如果(cx)=0转移到标号处执行。)

3操作:当(cx)=0时,(IP)=(IP)+8位位移

当(cx)!=0时,程序向下执行,jcxz什么都不做

相当于:if((cx)==0)jmp short 标号;

检测点9.2

补全编程,利用jcxz指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。

assume cs:code
code segment
 start: mov ax,2000h
        mov ds,ax
        mov bx,0
     s: mov ch,0    
        mov cl,[bx] 

jcxz ok ;当cx=0时,CS:IP指向OK

        inc bx      
        jmp short s 
    ok: mov dx,bx
        mov ax ,4c00h
        int 21h
code ends
end start

9.8 loop指令

1.loop为循环指令,所有的循环指令都是短转移,在对应的机器码中包含的是位移

2.loop标号 相当于

(cx)–;

if((cx)!=0)jmp short 标号;

检测点9.3

补全编程,利用loop指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。

assume cs:code 
code segment 
start:  mov ax,2000h 
        mov ds,ax 
        mov bx,0
      s:mov cl,[bx] 
        mov ch,0 
        inc cx      
        inc bx 
        loop s 
     ok:dec bx 
        mov dx,bx 
        mov ax,4c00h 
        int 21h 
code ends 
end start
执行loop s时,首先要将(cx)减1。
“loop 标号”相当于
dec cx
if((cx)≠0) jmp short 标号

9.9 根据位移进行转移的意义:方便程序段在内存中的浮动装配

9.10编译器对转移位移超界的检测:如果转移范围超界,编译器报错。形如jmp xxxx:xxxx的指令在debug下可用,但不能在源程序中写出。

实验8 分析一个奇怪的程序

该程序是否可以正常返回?

Program ex-8-1
assume cs:codesg
codesg segment
    mov ax,4c00h
    int 21h
start: mov ax,0            ;ax=0
    s: nop                 ;占一字节,机器码90
       nop                 ;占一字节,机器码90
       mov di,offset s     ;(di)=s偏移地址
       mov si,offset s2    ;(si)=s2偏移地址
       mov ax,cs:[si]      ;(ax)=jmp short s1指令对应的机器码EBF6
       mov cs:[di],ax      ;jmp short s1覆盖s处指令2条nop指令
   s0: jmp short s         ;执行s???? 未执行到这里,直接跳回mov ax,4c00h了
   s1: mov ax,0
       int 21h
       mov ax,0
   s2: jmp short s1       
       nop
codesg ends
end start
<-debug下的内容
注意到所谓的jmp short s实际上是EBF6这样的指令,F6为位移。根据每条指令的长度计算出被覆盖的nop指令移动F6个字节后指向那一条指令。

关于jmp指令的位移内容

当指令执行到s0:jmp short s时,该指令得到执行,编译器算出的ip位移量为8-18h=-16(补码F0),(ip)=(ip)+位移量=18h+(-16)=8,cs:8指向s;

当指令执行到s标段jmp命令时,第1个字节中的机器码为EBF6,给出的ip位移量为-10(补码F6),(ip)=(ip)+位移量=ah+(-10)=0,cs:0指向第一条指令。

实验9 显示三行welcome to masm(根据材料编程)

编程:在屏幕中间分别显示绿色,绿底红色,白色蓝底的字符串’welcome to masm!’

材料:80x25彩色字符模式显示缓冲区的介绍

1.缓冲区所在的内存地址:B8000H~BFFFFH(共32KB)

2.向该地址空间写入数据,写入的内容立即出现在显示器上。

3.显示器可以显示25行,每行80个字符,每个字符可以有256中属性

4.一个字符在显示缓冲区中占两个字节,分别存放字符的ASCII码和属性,低位字节存放字符ASCII码,高位字节存放属性

5.80x25模式下,一屏的内容在显示缓冲区占4000个字节。

6.显示缓冲区共8页,每页4KB

7.显示器可以显示任意一页的内容,一般显示第0页(B8000H~B8F9FH)的内容

8.在一页显示缓冲区中:

偏移

对应显示器的行数

000~09F

1

0A0~13F

2

F00~F9F

25

单元

对应显示器的列数

00 01

第1列

02 03

第2列

9E 9F

第80列

9.在显示缓冲区中,偶地址存放字符,奇地址存放字符属性

10.属性字节的格式

R 红色

G 绿色

B 蓝色

常用:

红底绿字0100 0010B

红底闪烁绿字1100 0010B

红底高亮绿字0100 1010B

黑底白字0000 0111B

白底蓝字0111 0001B

Program ex-9-1 自主解法

assume cs:code,ds:data,ss:stack
data segment
db 'welcome to masm!'
db 00000010B ;绿色(16)
db 00100100B ;绿底红字(17)
db 01110001B ;白底蓝字(18)
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start:
mov ax,0b800h
mov es,ax ;es=显示缓冲区
mov di,1660 ;第10行第40列
mov ax,data
mov ds,ax ;ds=data
mov ax,stack
mov ss,ax ;ss=stack
mov sp,16
mov si,0
mov cx,3
mov bx,16
s0: push cx
mov cx,16
s: mov ax,0
mov al,[si]
mov es:[di],ax
mov dl,[bx]
mov es:[di+1],dl
add di,2
inc si
loop s
sub di,32
add di,160
mov si,0
inc bx
pop cx
loop s0
mov ax,4c00h
int 21h
code ends
end start

Program ex-9-2 参考

assume cs:code,ds:data
data segment
db 'welcome to masm!'
data ends
code segment
start:mov ax,data
mov ds,ax
mov bx,0;ds:bx指向data字符串
mov ax,0b800h
mov es,ax
mov si,0;es:si指向显存
mov cx,16
s:mov al,[bx];字符赋值al
mov ah,02h;绿色
mov es:[si].720h,ax;写入第12行64列
mov ah,14h;绿底红色
mov es:[si].7c0h,ax;写入第13行64列
mov ah,71h;白底蓝色
mov es:[si].860h,ax;写入第14行64列
inc bx;指向下一字符
add si,2;指向下一显存单元
loop s
mov ax,4c00h
int 21h
code ends
end start

发表评论

滚动至顶部