汇编笔记_第九章


title: 汇编笔记_第九章
date: 2018-12-27 21:30:12

  • 笔记
    categories:
  • 汇编语言

转移指令的原理

8086CPU的转移指令分为以下几类:

  • 无条件转移指令(如:jmp
  • 条件转移指令
  • 循环指令(如:loop
  • 过程
  • 中断

操作符offset

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

例题:

assume cs:codesg
codesg segment

start:
mov ax,bx   ;mov ax,bx的机器码占两个字节
mov si,offset start
mov di,offset s0

mov ax,cs:[si]
mov cs:[di],ax

s0:
nop         ;nop的机器码占一个字节
nop

codesg ends
end start

jmp指令

  • jmp为无条件转移,可以只修改IP,也可以同时修改CS和IP;
  • jmp指令要给出两种信息:转移的目的地址转移的距离(段间转移、段内短转移、段内近转移)

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

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

  • 段内短转移
  • IP的修改范围为 -128~127

jmp short 标号的功能为:

  • (IP)=(IP)+8位位移;
  • 8位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
  • short指明此处的位移位8位位移;
  • 8位位移的范围位-128~127,用补码表示;
  • 8位位移由编译程序在编译时算出;

CPU在执行jmp short 标号指令时只需知道转移的位移就行;

jmp near ptr 标号

实现 段内近转移,(IP)=(IP)+16位位移;

  • 16位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
  • near ptr指明此处的位移位16位位移;
  • 16位位移的范围位-32769~32767,用补码表示;
  • 16位位移由编译程序在编译时算出

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

上面两个jmp指令相当于当前IP的转移位移;

jmp far ptr 标号实现的是 段间转移,又称远转移

  • (CS)=标号所在段的段地址;
  • (IP)=标号所在段中的偏移地址;
  • far ptr指明了指令用标号的段地址和偏移地址修改CS和IP;

转移地址在 寄存器 中的jmp指令

指令格式:

jmp 16位寄存器

功能:IP=(16位寄存器);

转移指令在 内存 中的jmp指令

jmp word ptr 内存的单元地址(段内转移)

功能:从内存的单元地址处开始存放着一个字,事转移的目的偏移地址;

mov ax,0123h
mov ds:[0],ax
jmp word ptr ds;[0]

执行后(IP)=0123h

mov ax,0123h
mov [bx],ax
jmp word ptr [bx]

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

mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]

执行后(CS)=0,(IP)=0123h,CS:IP指向0000:0123

mov ax,0123h
mov [bx],ax
mov word ptr [bx+2],0
jmp dword ptr[bx]

jcxz指令

  • jcxz指令位有条件转移指令;
  • 所有的有条件转移指令都是 短转移
  • 对应的机器码中包含转移的 位移,而不是目的地址,对IP的修改范围都为-128~127;
  • 指令格式: jcxz 标号,(如果(cx)=0,则转移到标号处执行);

例题:利用 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,ds:[bx]
jcxz ok
inc bx
jmp short s

ok:
mov dx,bx

mov ax,4c00h
int 21h

code ends
end start

loop指令

  • loop为循环指令;
  • 所有的循环指令都是短转移;

loop 标号:

  • (cx)=(cx)-1;
  • 如果 ((cx) eq 0),(IP)=(IP)+8位位移;
  • 8位位移=“标号”处的地址-loop指令后的第一个字节的地址;

例题:

;找到2000h段中第一个值为0的字节

assume cs:code
code segment
start:
mov ax,2000H
mob ds,ax
mov bx,0

s:
mov al,[bx]
mov ch,0
inc cx  ;若该字节为零,那么现在递增为1,之后的loop会使cx减一为零自动退出循环,
inc bx
loop s

ok:
dec bx      ;dec指令的功能和inc相反
mov dx,bx
mov ax,4c00h
int 21h

code ends
end start

根据位移进行转移的意义

jmp short 标号

jmp near ptr 标号

jcxz 标号

loop 标号

对IP的修改是根据转移目的地址和转移起始地址之间的 位移 来进行的,这样设计方便程序段在内存中的浮动装配;

编译器对转移位移超界的检测

原程序中出现转移范围超界的问题时,编译报错;
例如:

assume cs:code
code segment
start:
jmp short s
db 128 dup(0)
s:
mov ax,0ffffh
code ends
end start

jmp short s的转移范围为-128~127,IP最多向后移动127个字节;

但如果在debug中使用汇编指令jmp 2000:0100就没有问题,如果在源程序里使用也会报错;

https://www.cnblogs.com/31415926535x/p/10187942.html

(end)

原文地址:https://www.cnblogs.com/31415926535x/p/10187942.html