【笔记】8086汇编-转移指令的原理

前言:本篇仅仅是笔记,整理于2017/8/18,结构可能会略有混乱,见谅。

-定义:可以修改IP,或同时修改CS和IP的指令统称为转移指令。

-8086CPU转移行为有以下几类:

–段内转移:一个只修改IP的转移行为(jmp ax是其中一个实现方式)

–段间转移:同时修改CS和IP的转移指令

-由于转移指令对IP的修改范围不同,段内转移分为:

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

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

-8086CPU的转移至零分为以下几类:

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

–条件转移指令

–循环指令(如:loop【备注:loop会判断cx是否为0,如果不为0,则会跳转到标号处】)

–过程

–中断

-【9.1 操作符offset】

–操作原理:由编译器处理的伪指令

–功能:取得标号的偏移地址

–使用方法示例:

—s: mov ax, offset s

–【备注:这里的问题9.1涉及到了一个“无效”指令nop,它没有特殊效果,机器码占据一个字节】

-【9.2jmp指令】

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

–jmp指令给出了两种信息:

—1)转移的目的地址

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

–【备注:不同的给出目的地址的方法,对应了不同格式的jmp指令,也就有不同的距离】

-【9.3 依据位移进行转移的jmp指令】

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

—这实现的是段内短转移

–我们发现,汇编指令中的idata,总会出现在对应的机器指令中。

–但是,这里我们发现了一个问题,便是jmp short 标号这个指令的机器码并不包含绝对的ip值,并且,在我们将jmp指令之前的指令进行修改后,这里的指令的机器码仍然没有改变。

—原因:在这个指令所对应的机器码中,不包含转移的绝对地址,而是包含了相对位移,这是编译器根据汇编指令中的“标号”计算出来的。

–由此,我们总结出了这个指令的功能:(IP) = (IP) + 8位位移

—8位位移 = 标号处的地址 – jmp指令后的第一个字节的地址(因为IP的增加是在执行完jmp指令后的;确切来说是:将jmp指令读入后,IP会先指向下一条指令,之后再执行刚才读入的指令)

–【short指明此处的位移为8位位移】

–【备注:补码计算,源码取反(not)再加1】

–jmp near ptr 标号

—这一条指令实现段内近转移(16位位移)

—功能:(IP) = (IP) + 16位位移

-【6.4 转移的目的地址在指令中的jmp指令】

–实现:jmp far ptr 标号

–这是段间转移,又称远转移

–解释:far ptr说明了要用标号所在的段地址修改CS,用标号所在的偏移地址修改IP。

–关于这个指令的机器指令:

—汇编指令为jmp 0BBD:010B(这个值是由标号替换而成) 的机器指令是EA0B01BD0B,我们发现,第一个字节对应了jmp指令,之后两个字节是段地址,再之后两个字节是偏移地址。【可以这样记忆:此处段地址与偏移地址对人来说是要从右向左读的】

-【9.5 转移地址在寄存器中的jmp指令】

–jmp 16位reg,相当于直接修改ip的值

-【9.6 转移地址在内存中的jmp指令】

–1)jmp word ptr内存单位地址(只能实现段内转移)

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

—解释:从内存单元地址处开始,高地址处作为转移的段地址,低地址处作为偏移地址。【同样可以记忆成从右(高)向左(低)读】

—常见用法:我们将内存地址单元用bx记录,之后我们在存入高位地址时使用[bx+2]

–注意:mov word ptr [bx],offset start以及mov word ptr [bx+2],code,这些语句必须加上word ptr来表明是什么类型数据。

-【9.7 jcxz指令】

–jcxz指令为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移(-128~127)

–作用是:如果jcxz=0时,会进行跳转,反之则不进行跳转。

-【9.8 loop指令】

–loop指令是循环指令,所有的循环指令都是短转移。

–CX不等于0时才跳转

–【备注dec指令(decrease)是自减1】

-【9.9 根据位移进行转移的意义】

–前面的jmp short X, jmp near ptr X, jcxz X, loop X都是使用位移来进行转移

–这种设计,方便了程序段在内存中的浮动装配。

—因为指令间的相对位置是固定的,如果使用位移来定义,这个程序可以在内存的任意一处正常运行。

–【备注:跳转位移写在机器码的第一个字节上】

-【9.10 编译器对转移位移超界的检测】

–Jump out of range by n byte(s).【n表示超出的字节数】

-【注意:第二章中讲到的形如”jmp 2000:0”这样的指令只能在debug中使用,在汇编源程序中使用会报错】

-【实验八 跳转实验】

-【实验九 彩色输出】

–任务目标:编程,在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串”welcome to masm!”

–知识储备:

—80×25彩色字符模式显示缓冲区(以下简称为显示缓冲区)的结构:

—内存地址空间中,B8000H~BFFFFH共32KB的空间,为80×25彩色字符模式(以下简称“模式”)的显示缓冲区。特点是:向这个地址空间写入的数据,会立即出现在显示器上。

—在这一模式下,显示器可以显示25行,每行80个字符,每个字符额可以有256种属性(背景色、前景色、闪烁、高亮等组合信息)

—一个字符要占据两个字节:分别存放字符ASCII码和属性。

—缓冲区分为8页,每页4KiB(每页均是80×25),显示器可以显示任意一页的内容,一般情况显示第0页。

—如果以每一页起始为段地址,则

—-偏移000~09F对应第一行(80个字符,160个字节)

—-偏移0A0~13F对应第二行

—-偏移140~1DF对应第三行

—一个字符低8位存储ASCII码,高八位存储属性。

—-由此我们得出结论,在显示缓冲区,偶地址(包含0)存放字符,奇地址存放属性。

—关于属性:

—-7号位BL,记录闪烁,1闪0不闪

—-6、5、4号位依次记录背景RGB

—-3号位记录高亮,1亮0不亮

—-2、1、0号位依次记录前景RGB

—-【备注:RGB属性仅能设置0或1】

—-【注意:闪烁效果仅仅能在全屏DOS方式下看到】

–设计分析:

—主要思路:将字符存入→赋予属性

—字符存入:

—-将原始字符存入一个段中,之后将这个段的每个字符存放在奇数的目标位置,并循环3次。bx定位最终显示的每行起始数据存放位置,di定位每行每个字符存放位置,si定位原始位置。

—赋予属性:

—-首先确定需求,

—–第一行(黑底绿字)字符属性:00000010B

—–第二行(绿底红字)字符属性:00100100B

—–第三行(白底蓝字)字符属性:01110001B

—–三行的属性不同,故而可以设计三个循环来完成属性赋值。

—接下来分析每行分布:每行有80个字符,160个字节,所以:

—-段地址定位第0页基础地址:B800H

—-第一行偏移地址:000H~09FH

—-第二行偏移地址:0A0H~13FH

—-第三行偏移地址:140H~1DFH

—-这个将由bx存储

—之后,要对每一个属性存放位置进行定位,故而我们用di存储。

—以上,要设置两层循环,内层每次循环让di+2,外层每次循环后将di赋1,将bx加A0H,属性提前存到数据段中,使用si定位,每个属性占1个字节,所以我们要让外循环每次对si自增1,将属性值赋给ax。

-【详解实验八】

–结论:利用位移的跳转并不是绝对位置,所以不能直接将这个指令复制到其它位置使用。此时计算方法:标号位置=位移+jmp指令后第一个字节所在位置

-【详解实验九】

–实验记录:Win7旗舰版下无法正常显示,即便使用mov ah,0与int 16h强行防止自动跳转仍然无显示。