汇编笔记

­
­
­
­
­
改错:
(1)1kb的存储器有1024个存储单元,每个单元的编号是从0-1023
(2)1kb的存储器可以存储8*1024个bit,1024个byte
(3)1GB,1MB,1KB分别是1*1024*1024*1024byte,1*1024*1024byte,1*1024 byte
(4)地址总线:(8080)16根,(8088)20根,(80286)24根,(80386)32根寻址分别为:64KB,1MB,16MB,4GB
(5)数据总线:(8080)8根,(8088)8根,(8086)16根,(80286)16根,(80386)32根,一次传送的数据为:8B,8B,16B,16B,24B
(6)从内存中读取1024字节数据,8086至少要读512次,80386至少读取256次
(7)在存储器中数据和程序以2进制形式存放
­
­
汇编语言组成:
1.汇编指令:机器码的助记符,有对应的机器码
2.伪指令:没有对应的机器码,有编译器执行,计算机并不执行
3.其他符号:如:+,-,*,/,等有编译器识别,没有对应的机器码
汇编语言的核心是汇编指令,他决定了汇编语言的特性。
存储单元:
电子计算机的最小信息单位是bit,也就是一个二进制位。8个bit组成一个byte,也就是通常讲的一个字节。微型机存储器的存储单元
可以存储一个字节,即8个二进制位。一个存储器有128个存储单元,它可以存储128个字节。
cpu要想进行数据的读写,必须和外部器件(芯片)进行3类信息的交互:
1.存储单元的地址
2.器件的选择,读或写的命令(控制信息)
3.读或写的数据(数据信息)
地址总线:指定存储单元的;
一个cpu有N根地址线,则可以说这个cpu的地址总线的宽度为N,这样cpu最多可以寻找2的N次方个内存单元
数据总线:传输数据的
8根数据总线一次传送一个字节,16根数据总线一次可传送2个字节.
控制总线:对外部器件的控制.控制总线是一些不同控制线的集合。有多少跟 控制线,就意味着cpu提供了对外部器件的多少种控制。控制总线决定cpu对外部器件的控制能力.
­
­
­
运算器进行信息处理;寄存器进行信息存储;控制器控制各种器件进行工作;内部总线连接各种器件,在它们之间进行数据的传送。
8086CPU 有14个寄存器,每个寄存器有一个名称。都是:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW.
8086CPU 所有寄存器都是16位的,可以存放两个字节。AX,BX,CX,DX四个寄存器通常用来存放一般性的数据,被称为通用寄存器。
8086CPU 的AX,BX,CX,DX四个寄存器都可分为两个独立使用的8位寄存器来用:
AX 可分为AH,AL
BX 可分为BH,BL
CX 可分为CH,CL
DX 可分为DH,DL
字在寄存器中的存储
字节:记为byte,一个字节由8个比特组成,可以存在8位寄存器中
字:记为word,一个字有两个字组成,这两个字节分别成为这个字的高位字节和低位字节。
在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的。
  
CPU 通过地址总线送入存储器的必须是一个内存单元的物理地址。在CPU向地址总线上发送物理地址之前,必须在内部先行成这个物理地址。不同的CPU有不同的形成物理地址的方式。
­
­
8086CPU 要读写内存时:
(1)CPU 中的相关部件提供两个16为地址,一个称为段地址,另一个称为偏移地址;
(2) 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件;
(3) 地址加法器将两个16位地址合成为一个20位的物理地址;
(4) 地址加法器通过内部总线将20位物理地址送入输入输出控制电路;
(5) 输入输出控制电路将20位物理地址送上地址总线;
(6)20 位物理地被地址总线传送到存储器.
地址加法器采用物理地址=段地址*16+偏移地址的方法合成物理地址.
­
­
" 段地址*16+偏移地址=物理地址"的的本质含义是:CPU在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址.
由于8086CPU用"基础地址(段地址*16)+偏移地址=物理地址"的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存
有两点需要注意:段地址*16必然是16的倍数,所以一个段的起始地址也一定是16的倍数:偏移地址为16为,16为地址的寻址能力为64KB,所以一个段的长度最大为64KB
­
段寄存器:
8086cpu 有4个段寄存器:CS,DS,SS,ES;当8086CPU要访问内存时由这4个寄存器提供内存单元的段地址。
CS 和IP是8086CPU中两个最关键的寄存器,他们指示了CPU当前要读取得指令的地址。CS为代码段寄存器,IP为指令指针寄存器,从名称上看出他们和指令的关系
在8086PC机中,任意时刻,设CS中的内容为M, IP中的内容为N,8086CPU将从内存M*16+N单元开始,读取一条指令并执行。
­
­
­
" 段地址*16+偏移地址=物理地址"的的本质含义是:CPU在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址.
由于8086CPU用"基础地址(段地址*16)+偏移地址=物理地址"的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存
有两点需要注意:段地址*16必然是16的倍数,所以一个段的起始地址也一定是16的倍数:偏移地址为16为,16为地址的寻址能力为64KB,所以一个段的长度最大为64KB
­
段寄存器:
8086cpu 有4个段寄存器:CS,DS,SS,ES;当8086CPU要访问内存时由这4个寄存器提供内存单元的段地址。
CS 和IP是8086CPU中两个最关键的寄存器,他们指示了CPU当前要读取得指令的地址。CS为代码段寄存器,IP为指令指针寄存器,从名称上看出他们和指令的关系
在8086PC机中,任意时刻,设CS中的内容为M, IP中的内容为N,8086CPU将从内存M*16+N单元开始,读取一条指令并执行。
­
­
8086CPU 的工作过程可以简要描述如下:
(1) 从CS:IP指向内存单元读取指令,读取得指令进入指令缓冲器;
(2)IP=IP+ 所读取指令的长度,从而指向下一条指令;
(3) 执行指令,转到步骤(1).
在8086CPU加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS=F000H.IP=FFFFH,即8086机刚启动时,CPU从内存FFFF0H单元中读取指令执行,FFFF0H单元中的指令时8086CPU开机后执行的第一条指令
­
我们可以说,CPU将CS:IP指向的内存单元中的内容看作指令,因为,在任何时候,CPU将CS,IP中的内容当作指令的段地址和偏移地址,用他们合成指令的物理地址,到内存中读取指令码,执行。如果说,内存中的一段信息曾被CPU执行过的话,那么,他说在的内存单元必然被CS:IP指向过。
­
MOV 指令被称为传送指令。
能够改变CS,IP的内容的指令被称为转移指令,如(JMP指令)修改CS,IP的内容:"JMP 段地址:偏移地址"
JMP 2AE3:3, 执行后,CS=2AE3H.IP=0003H,CPU将从2AE33H出读取指令。
JMP 段地址:偏移地址 指令的功能为:用指令中给出的段地址修改CS, 偏移地址修改IP
若想仅修改IP的内容,可用指令"JMP某一合法寄存器"完成。
JMP ax, 指令执行前:AX=1000H.CS=2000H,IP=0003H
   指令执行后:AX=1000H.CS=2000H,IP=1000H
JMP bx, 指令执行前:BX=0B16H.CS=2000H,IP=0003H
   指令执行后:BX=0B16H.CS=2000H,IP=0B16H
JMP  AX,在含义上类似MOV IP.AX这样的指令。
­
(2)Debug 功能:
   *R 命令查看,改变CPU寄存器的内容;
  *D命令查看内存中的内容;
  *E命令改写内存中的内容
  *U命令将内存中的机器指令翻译成汇编指令
  *T命令执行一条机器指令;
  *A命令以汇编指令的格式在内存中写入一条机器指令.
­
­
­
­
从内存的角度继续学习寄存器;
字单元,即存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成,高地址内存单元存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节.
­
我们将起始地址为N的字单元简称为N地址字单元,比如一个字单元由2,3两个内存单元组成,则这个内存单元组成,则这个字单元的起始地址为2,我们可以说这是2地址字单元
­
DS: 通常用来存放要访问数据的段地址. 数据段的段地址默认放在ds中,指令执行时,CPU会自动从DS中取出.
8086CPU 不支持将数据直接送入段寄存器的操作(这属于8086CPU硬件设计问题),可以用一个寄存器来进行中专,即先将1000H送入一个一般的寄存器,如bx,在将bx中的内容送入ds
cs (code segment)是代码段寄存器,放代码段的段地址他里面的内容和ip里面的内容和起来就可以找到当前执行的指令,
ds (data segment)是数据段段寄存器 放数据段的段地址,根据段地址*16d+偏移量就可以得到物理地址
从内存单元到寄存器的格式是:"MOV 寄存器名,内存单元地址",从寄存器到内存单元则是:"MOV 内存单元地址,寄存器名"。
MOV 指令可以有以下几种形式:
MOV 寄存器,数据
MOV 寄存器,寄存器
MOV 寄存器,内存单元
MOV 内存单元,寄存器
MOV 段寄存器,寄存器
MOV 寄存器,段寄存器
MOV 内存单元,段寄存器
MOV 段寄存器,内存单元
­
ADD:
ADD 寄存器,数据
ADD 寄存器,寄存器
ADD 寄存器,内存单元
ADD 内存单元,寄存器
­
­
数据段小结:
1 字在内存中存储时,要用两个连续的内存单元来存放,字的地位字节存放在低地址单元中,高字节存放在高地址单元中。
2 用MOV指令要访问内存单元,可以在MOV指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中.
3[address] 表示一个偏移地址为address的内存单元。
4 在内存中和寄存器之间传送字型数据时,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应。
5MOV,ADD,SUB 是具有两个操作对象的指令,JMP是具有一个操作对象的指令
­
栈:
  8086CPU 中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中,任意时刻,SS:SP指向栈顶元素。PUSH指令和POP指令执行时,CPU从SS和SP得到栈顶的地址
  PUSH AX 的执行,由以下两步完成:
   (1) SP=SP-2,SS:SP 指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
   (2) 将AX中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶
­
­
­
( 注意: 入栈时,栈顶从高地址向底地址方向增长)
POP AX 的执行过程和PUSH AX刚好相反
(1) 将SS:SP指向的内存单元处的数据送入AX中
(2) SP=SP+2,SS:SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶.
( 注意: 图中,出栈后,SS:SP指向新的栈顶1000EH,POP操作前的栈顶元素,1000CH处的2266H依然存在,但是,它已不在栈中.当再次执行PUSH等入栈指令后,SS:SP移至1000CH,并在里面写入新的数据,它将覆盖.)
­
栈顶超界问题:
80886CPU 不保证我们对栈的操作不会超界.
PUSH,POP 指令是可以在寄存器和内存之间传送数据的.
PUSH 寄存器;将一个寄存器中的数据入栈
POP 寄存器;出栈.用一个寄存器收入栈的数据
­
PUSH 段寄存器 ;将一个段寄存器中的数据入栈
POP 段寄存器  ;出栈,用一个段寄存器收入栈的数据
­
PUSH 内存单元;将一个内存单元处的字入栈(注意:栈操作都是以字为单位.)
POP   内存单元;出栈,用一个内存字单元接收出栈的数据
­
指令执行时,CPU要知道内存单元的地址.可以在PUSH,POP指令中给出内存单元的偏移地址,段地址在指令执行时,CPU从DS中取得.
注意:PUSH ,POP等栈操作指令,修改的只是SP,也就是说,栈顶的变化范围最大为0--FFFFH
­
栈段:
PUSH,POP 等指令再执行的时候只修改SP,所以栈顶的变化范围是0--FFFFH,从栈空时候的SP=0,一直压栈.直到栈满时SP=0;如果再次压栈.栈顶将环绕.覆盖了原来栈中的内容.所以栈的容量最大为64KB
注意:Debug的T命令在执行修改寄存器SS的指令时,下一条指令也紧接着被执行.
­
补充:
Debug 使用:
Debug 在执行D命令时,将段地址送入 DS中.D命令也是提供了一种符合CPU机理的格式."D段寄存器:偏移地址",以段寄存器中的数据为段地址SA,列出从SA:偏移地址开始的内存区间中的数据 -D DS:10 18 ;-D CS:0 ;-D SS:0
E,A,U 命令中使用段寄存器
在E,A,U这些可以带有内存单元地址的命令中,也可以同D命令一样,用段寄存器表示内存单元的段地址
­
­
一个源程序从写出到执行的过程
1 编写汇编源程序(产生一个存储源程序的文本文件)
2 对源程序进行编译连接
[1] 汇编编译程序对源程序文件中的源程序进行编译,产生目标文件
[2] 再用连接程序对目标文件进行连接,生成可在操作系统中直接运行的可执行文件
可执行文件包含两部分内容:
* 程序(从源程序中的汇编指令翻译过来的机器码)和数据(源程序中定义的数据)
* 相关的描述信息(比如,程序有多大,要占用多少内存空间等)
3 执行可执行文件中的程序
­
­
伪指令:由编译器来执行的指令
(1)XXX segment
     ......
  XXX ends
(2)END ( 汇编程序的结束标记)
(3)Assume( 假设)将有特定用途的段和相关的段寄存器关联起来即可
源程序中的"程序"(我们这里所说的程序就是指源程序中最终有计算机执行,处理的指令或数据)
注意(将源程序文件中的所有内容称为源程序,将源程序中最终由计算机执行,处理的指令或数据,称为程序.程序最先以汇编指令的形式存在源程序中,经编译,连接后转变为机器码,存储在可执行文件中.)
­
标号:一个标号指代一个地址
与结束相关的概念区别:
通知编译器一个段结束 相关指令[段名 Ends ] 指令性质 [伪指令] 由编译器执行
通知编译器程序结束 相关指令[ End ]        指令性质 [伪指令] 由编译器执行
程序返回 相关指令[ Mov ax,4c00H int 21H ]   指令性质[汇编指令]由CPU执行
­
生成程序最后连接的作用:
* 当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件.
* 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接到一起,生成一个可执行文件
* 一个源程序编译后,得到了存有机器码的目标文件,目标文件的有些内容还不能直接用来生成可执行文件,连接程序将这些内容处理为最终的可执行信息.所以,在只有一个源程序文件,而又不许要某个库中的子程序的情况下,也必须用连接程序对目标文件进行处理,生成可执行文件.
­
操作系统的外壳
操作系统是由多个功能模块组成的庞大,复杂的软件系统.任何通用的操作系统,都要提供一个称为shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统进行工作.
DOS 中有一个程序command.com.这个程序在DOS中称命令解释器,也就是DOS系统的Shell.
­
DOS 启动时,先完成其他重要的初始化工作.然后运行command.com.command.com运行后,执行完其他的相关任务后,再屏幕显示出由当前盘符和当前路径组成的提示符,比如:"C:/"或者"c:/windows"等,然后等待用户的输入
用户可以输入所要执行的命令比如:cd,dir,type等.这些命令由command执行.command执行完这些命令后,再次显示由当前盘符和当前路径组成的提示符,等待用户的输入.
如果用户要执行一个程序,则输入该程序的可执行文件的名称,command将该文件装入内存,设置CS:IP指向程序的入口.此后,command暂停运行,CPU运行程序结束后,返回command中,
Command 再次显示由当前盘符和当前路径组成的提示符,等待用户的输入.
汇编程序从写到执行的过程
­
"( )"描述性的符号来表示一个寄存器或一个内存单元中的内容
(ax) 表示ax中的内容,(al)表示al中的内容
"()" 中的内存单元的地址为物理地址
注意:"()"中元素可以有三种类型:*寄存器名;*段寄存器名;(3)内存单元的物理地址(一个20为数据)。比如:(ax),(ds),(al),(cx),(20000H),((ds)*16+(bx))等是正确的用法;
(2000H),(2000:0),((ds):1000H)等不是正确的用法
一些应用:
(1) ax 中的内容为0010H,可以这样描述:(ax)=0010H;
(2) 2000:1000 处的内容为0010H,可以描述(21000H)=0010H
(3) 对于MOV AX,[2]的功能,可以描述:(AX)=((DS)*16+2);
(4) MOV [2],AX 的功能,可以描述((DS)*16+2)=(AX);
(5) 对于ADD AX,2的功能,可以描述(AX)=(AX)+2;
(6) 对于ADD AX,BX的功能,可以描述(AX)=(AX)+(BX);
(7) 对于PUSH AX的功能,可以描述
(SP)=(SP)-2
((SS)*16+(SP))=(AX)
(8) 对于POP AX的功能,可以描述:
    (AX)=((SS)*16+(SP))
(SP)=(SP)+2
­
LOOP 指令 LOOP 标号;
步骤:
1,(CX)=(CX)-1
2 判断CX中的值,不为零则转至标号处执行程序,如果为零则想下执行
CX 和LOOP指令想配合实现循环功能的三个要点:
(1) 在CX中存放循环次数;
(2)LOOP 指令中的标号所标志地址要在前面;
(3) 要循环执行的程序段,要写在标号和loop指令的中间
程序框架:
MOV CX, 循环次数
S:  
循环执行的程序段
LOOP S
­
汇编程序中指令的含义:
"MOV AL,[0]" 含义:(AL)=0.将常量0送入al中(与MOV AL,0含义相同);
"MOV AL,DS:[0]", 含义:AL=((DS)*16+0),将内存单元中的数据送入AL中 ;
"MOV AL,[BX]", 含义:AL=((DS)*16+(BX)),将内存单元中的数据送入AL中;
"MOV AL,DS:[BX]", 含义:与"MOV AL,[BX]"相同.
­
我们可以看出:
1 ,在汇编源程序中,如果用指令访问一个内存单元,则在指令中必须用"[...]"来表示内存单元,如果在"[]"里用一个常量idata直接给出内存单元的偏移地址,就要在"[]"的前面显式地给出段地址所在的段寄存器
2 如果在"[]"里用寄存器,比如bx,间接给出内存单元的偏移地址,则段地址默认在ds中,当然,也可以显式地给出段地址所在的段寄存器.
DOS 方式下,一般情况,0:200-0:300空间中没有系统或其他程序的数据或代码
­
将一个字符串"BaSic"的大写字母转变为小写,小写转变为大写的两种方法:
1 将用到And和Or指令
2 用到加减指令
数学化的描述为 :(AX)=((DS)*16+(BX)+200)
指令的几种形式:
MOV AX,[200+BX]
MOV AX,200[BX]
MOV AX,[BX].200
­
SI 和DI是8086CPU中和 BX功能相近的寄存器,SI和DI不能够分成两个8为寄存器来使用
数学化描述:(AX)=((DS)*16+(BX)+(SI))
该指令也可以写成如下格式(常用):
MOV AX.[BX][SI]
­
数学化的描述:(AX)=((DS)*16+(BX)+(SI)+IDATA)
该指令也可以写成如下格式(常用):
MOV AX,[BX+20+SI]
MOV AX,200[BX][SI]
MOV AX,[BX].200[SI]
MOV AX,[BX][SI].200
­
REG的集合包括:AX,BX,CX,DX,AH,Al,BH,Bl,CH,CL,DH,DL,SP,BP,SI,DI;
SREG 的集合包括:DS,SS,CS,ES
总结:8086CPU中,
(1) 只有4个寄存器可以在"[]"中来进行内存单元的寻址(BX,SI,BP,DI)
这些是错误的指令:
MOV AX,[CX]
MOV AX,[AX]
MOV AX,[DX]
MOV AX,[DS]
(2) 在[..]中,这4个寄存器可以单个出现,或只能以4种组合出现:BX和SI,BX和DI ,BP和SI,BP和DI
(3) 只要在[..]中使用寄存器BP,而指令中没有显性的给出段地址,段地址就默认在SS中
­
指令在执行前,所要处理的数据可以在三个地方:CPU内部,内存,端口
­
汇编语言中的数据位置的表达:
(1) 立即数(idata)
对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),在汇编语言中称:立即数(idata),在汇编指令中直接给出
(2) 寄存器 指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名;
(3) 段地址(SA)和偏移地址(EA)
指令要处理的数据在内存中,在汇编指令中可用[X]的格式给出EA,SA在某个段寄存器中
 
寻址方式:
­
­
8086CPU 的指令,处理两种尺寸的数据,BYTE和WORD
(1) 通过寄存器名指明要处理的数据的尺寸
(2) 在没有寄存器名的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以为WORD或BYTE 如:MOV WORD PTR DS:[0],1
(3) 其他方法
有些指令已经默认了访问的是字单元还是字节单元,比如:PUSH[1000H]就不用指明访问的是字单元还是字节单元,因为PUSH指令只进行字操作
­
DIV 指令(除法)
(1): 除数:有8位和16位两种,在一个寄存器或内存单元中
(2) 被除数:默认放在AX或DX和AX中,
如果除数为8位,被除数则为16位,默认在AX中存放,
如果除数为16位,被除数则为32位,在 DX和AX中存放,DX存放高16位, AX存放低16位
(3) 结果:
如果除数为8位,则 AL存储除法操作的商,AH存储除法操作的余数
如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数
格式:
DIV REG
DIV 内存单元
伪指令DD
DD 是用来定义DWORD(DOUBLE WORD,双字)型数据的
DUP 操作符
在汇编中同DB,DW,DD等一样,也是由编译器识别处理的符号,它和DB,DW,DD等数据定义伪指令配合使用的,用来进行数据的重复;
DB 重复的次数 DUP(重复的字节型数据)
DW 重复的次数 DUP(重复的字型数据)
DD 重复的次数 DUP(重复的双字数据)
­
可以修改IP,或同时修改CS和IP的指令统称为转移指令,转移指令就是可以控制CPU执行内存中某处的代码的指令
8086CPU 的转移行为有一下几类:
# 只修改IP时,程为段内转移,比如:JMP AX
# 同时修改CS和IP时,称段间转移,比如:JMP 1000:0
由于转移指令对IP的修改范围不同,段内转移又分为:短转移和近转移
# 短转移IP的修改范围为-128-127
# 近转移IP的修改范围为-32768-32768
8086CPU 的转移指令分
# 无条件转移指令(JMP)
# 条件转移指令
# 循环指令(LOOP)
# 过程
# 中断
­
操作符offset 在汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址
JMP 为无条件转移指令,可以只修改IP,也可以同时修改CS和IP
JMP 指令要给出两种信息
# 转移的目的地址
# 转移的距离(段间转移,段内短转移,段内近转移)
不同的给出目的地址的方法,和不同的转移位置,对应有不同的格式的JMP指令
依据位移进行转移的JMP指令
JMP  SHORT 标号(转到标号处执行指令)
这种格式的JMP指令实现的是段内短转移,它对IP的修改范围为-128-127,也就是是说,它向前转移时可以最多超越128个字节,向后转移可以最多超过127个字节。JMP指令中的"short"符号,说明指令进行的是短转移。JMP指令中的"标号"是代码段中的标号,指明了指令要转移的目的地,转移指令结束后, CS:IP应该指向标号处的指令
CPU 在执行JMP指令的时候并不需要转移的目的地址
在"JMP SHORT 标号"指令所对应的机器码中,并不包含转移的目的地址,而是包含的是转移的位移,这个位移,是编译器根据汇编指令中的"标号"计算出来的
­
实际上,指令"JMP SHORT 标号"的功能为:(IP)=(IP)+8位位移
(1)8 位位移="标号"处的地址-JMP指令后的第一个字节的地址
(2)SHORT 指明此处的位移为8位位移
(3)8 位位移的范围为-128-127,用补码表示;
(4)8 位位移由编译程序在编译时算出
还有一种和指令"JMP SHORT 标号"功能相近的指令格式:JMP NEAR PTR 标号,它实现的是段内近转移
指令"JMP NEAR PTR标号"的功能为:(IP)=(IP)+16位位移
(1)16 位位移=指令"标号"处的地址-JMP指令后的第一个字节的地址
(2)NEAR PTR 指明此处的位移为16位位移,进行的是段内近转移;
(3)16 位位移的范围为-32768-32767,用补码表示;
(5)16 位位移由编译程序在编译时算出。
­
上面是相对于当前IP的转移位移
­
指令"JMP FAR PTR 标号"实现的是段间转移(远转移)
(CS)= 标号所在的段的段地址;(IP)=标号在段中的偏移地址 。
FAR PTR 指明了指令用标号的段地址和偏移地址修改CS和IP
­
转移地址在寄存器中的JMP指令
JMP 16 为寄存器
功能:(IP)=(16位寄存器)
转移地址在内存中的JMP指令
(1)JMP WORD PTR 内存单元地址(段内转移)
功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址
(2)JMP DWORD PTR 内存单元地址(段间转移)
功能:从内存单元地址开始存放着两个字,高地址的字是转移的目的段地址,低地址处是转移的目的偏依地址
(CS)=( 内存单元地址+2)
(IP)= (内存单元地址)
­
JCXZ 指令(有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址,对IP的修改范围都为:-128-127)
指令格式:JCXZ 标号(如果(CX)=0,转移到标号处执行)
操作:当(CX=0)时,(IP)=(IP)+8位位移
8 位位移="标号"处的地址-JCXZ指令后的第一个字节的地址
8 位位移的范围为-128-127,用补码表示
8 位位移由编译程序在编译时算出
当(CX)!=0时,程序向下执行(相当于if(CX)==0 JMP SHORT 标号)
­
LOOP 指令循环指令,所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址,对IP的修改范围都为-128-127
指令格式:LOOP 标号((CX)=(CX)-1,如果(CX)!=0,转移到标号处执行)
操作:
(1)(CX)=(CX)-1;
(2) 如果(CX)!=0,(IP)=(IP)+8位位移
8 位位移="标号"处的地址-JCXZ指令后的第一个字节的地址
8 位位移范围为-128-127,用补码表示
8 位位移由编译程序在编译时算出
如果(CX=0),程序向下执行
功能相当于
(CX)--;
If((CX)!=0)JMP SHORT 标号
­
编译器可对转移位移超界检测
­
一个字符在显示缓冲区中要占两个字节,分别存放字符的ASCII码和属性,低位字节存储字符的ASCII码,高位字节存储字符的属性
一个在屏幕上显示的字符,具有前景色(字符色)和背景色,字符可以高亮度和闪烁的方式显示,前景色,背景色,闪烁,高亮等信息被记录在属性字节中。
­
CALL 和 RET指令 都是转移指令,都修改IP,或同时修改CS和IP
RET 指令用栈中的数据,修改IP的内容,从而实现近转移;
RETF 指令用栈中的数据,修改CS和IP的内容,从而实现远转移
CPU 执行RET指令时,进行下面操作:
(1) (IP)=((SS)*16+(SP))
(2) (SP)=(SP)+2
CPU 执行RETF指令时,进行下面操作:
(1)(IP)=((SS)*16+(SP))
(2)(SP)=(SP)+2
(3)(CS)=((SS)*16+(SP))
(4)(SP)=(SP)+2
CPU 执行CALL指令时,进行下面操作:
(1) 将当前的IP或CS和IP压入栈中
(2) 转移
CALL 指令不能实现短转移,除此,CALL指令实现转移的方法和JMP指令的原理相同
根据位移进行转移的CALL指令
执行CALL指令的一种格式,
(1)(SP)=(SP)-2
   ((SS)*16+(SP))=(IP)
(2)(IP)=(IP)+16 位位移
16 位位移="标号"处的地址-CALL指令后的第一个字节的地址
16 位位移范围-32768-32768
16 位位移由编译器在编译时算出
­
转移的目的地址在指令中的CALL指令
前面的CALL指令,其对应的机器指令中并没有转移的目的地址,而是相对于当前IP的转移位移
指令"CALL FAR PTR标号"实现的是段间转移
(1)(SP)=(SP)-2
  ((SS)*16+(SP))=(CS)
  (SP)=(SP)-2
  ((SS)*16+(SP))=(IP)
(2)(CS)= 标号所在段的段地址
   (IP)= 标号在段中的偏移地址
转移地址在寄存器中的CALL指令
CALL 16 位寄存器
(SP)=(SP)-2
((SS)*16+(SP))=IP
(IP)=(16 位寄存器)
­
转移地址在内存中的CALL指令
(1)CALL WORD PTR 内存单元地址
(2)CALL DWORD PTR 内存单元地址
­
MUL 指令
(1) 要么都是8位,要么都是16位,如果是8位,默认放在AL中,另一个放在8位放在寄存器或内存字节单元中;如果是16位,一个默认在AX中,一个默认放在16位寄存器或内存字节单元中
(2) 结果:如果是8位乘法,结果默认放在AX中,如果是16位乘法,结果高位默认在DX 中存放,低位在AX中存放。
格式:
MUL REG
MUL 内存单元
内存单元可以用不同的寻址方式给出 比如:
MUL BYTE PTR ds:[0]
含义为: (AX)=(AL)*((DS)*16+0)
MUL WORD PTR [BX+SI+8]
含义为:
(AX)=(AX)*((DS)*16+(BX)+(SI)+8) 结果的低16位
(DX)=(AX)*((DS)*16+(BX)+(SI)+8) 结果的高16位
­
标志寄存器:
(1) 用来存储相关指令的某些执行结果
(2) 用来为CPU执行相关指令提供行为依据
(3) 用来控制CPU的相关工作方式
简称flag,它是按位起作用的,每一位都有专门的含义,记录特定的信息
­
­
Flag 的1,3,5,12,13,14,15位在CPU中没有使用,不具任何含义。而0,2,4,6,7,8,9,10,11位都具有特殊含义
ZF, 零标志位,它记录相关指令执行后,其结果是否为0,如果结果为0,那么ZF=1,如果结果不为0,那么ZF=0.
­
注意:在8086CPU的指令集中,有的指令的执行影响标志寄存器,比如:ADD,SUB,DIV,INC,OR,AND 等,它们大都是运算指令(进行逻辑或算术运算);有的指令的执行对标志寄存器没有影响,比如:MOV,PUSH,POP等,它们大都是传送指令。
­
PF, 奇偶标志位,它记录相关指令执行后,其结果的所有二进制位中1的个数是否为偶数,如果1的个数为偶数,PF=1,如果位奇数,PF=0
­
SF ,符号标志位,它记录相关指令执行后,其结果是否为负,如果为负,SF=1,如果非负,SF=0
SF ,就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF就的值则没有意义
­
CF, 进位标志位,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高的进位值,或从更高位的借位值
对于位数为N的无符号数来说,其对应的二进制信息的最高位,既第N-1位,就是它的最高有效位,
OF 标志位,OF记录了有符号数运算的结果是否发生了溢出,如果发生溢出,OF=1,如果没有OF=0.
一定要注意OF和CF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位
­
ADC 是带进位加法指令,它利用了CF上记录的进位值
格式:ADC操作对象 1,操作对象2
功能:操作对象1=操作对象1+操作对象2+CF
­
SBB 是带借位减法指令,它利用了CF位上记录的借位值
格式:SBB 操作对象1,操作对象2
功能:操作对象1=操作对象1-操作对象2-CF
­
CMP 比较指令,CMP的功能相当于减法指令,只是不保存结果。CMP指令执行后,将对标志寄存器产生影响
格式:CMP 操作对象1,操作对象2
功能:计算操作对象1-操作对象2 但并不保存结果,仅仅根据计算结果对寄存器进行设置
­
检测比较结果的条件转移指令
" 转移"指的是它能够修改IP,而"条件"指的是它可以根据某种条件,决定是否修改IP
比如:JCXZ就是一个条件转移指令,它可以检测CX中的数值,如果(CX)=0,就修改IP,
否则什么也不做。所以条件转移指令的转移位移都是[-128,127]
­
大多数条件转移指令都检测寄存器的相关标志位(CMP指令影响的那些,表示结果的标志位),根据检测的结果来决定是否修改IP,这些条件转移指令通常都和CMP想配合使用,就好象CALL和RET指令通常相配合使用一样
­
因为CMP指令可以同时进行两种比较,无符号数比较和有符号数比较,所以CMP指令的比较结果进行转移的指令也分为两种,既根据无符号数的比较结果进行转移的条件转移指令,它们检测ZF,CF的值;和根据有符号数的比较结果进行转移的条件转移指令,它们检测SF,OF,和ZF 的值
­
无符号数的比较结果进行转移的条件转移指令
­
有符号数的比较结果进行转移的条件转移指令的工作原理和无符号的相同,只是检测了不同的标志位。
DF 标志和串传送指令
DF 方向标志位,在串处理指令中,控制每次操作后SI,DI的增减。
DF=0 每次操作后SI,DI递增;
DF=1 每次操作后SI,DI递减;
­
串传送指令
格式:MOVSB
功能:执行MOVSB指令相当于进行下面几步操作
(1)((ES)*16+(DI))=((DS)*16+(SI))
(2) 如果DF=0,则:(SI)=(SI)+1
               (DI)=(DI)+1
   如果DF=1 则:(SI)=(SI)-1
               (DI)=(DI)-1
MOVSB 的功能是将DS:SI指向的内存单元中的字节送入ES:DI中,然后根据标志寄存器DF位的值,将SI和DI递增或递减
­
MOVSW 的功能是将DS:SI指向的内存单元中的WORD送入ES:DI中,然后根据标志寄存器DF位的值,将SI和DI递增2或递减2
MOVSB 和MOVSW进行的是串传送操作中的一个步骤,一般来说,MOVSB和MOVSW都和REP配合使用
REP MOVSB 可以循环实现(CX)个字符的传送
­
8086CPU 提供下面两条指令对DF位进行设置
CLD 指令:将标志寄存器的DF位置0
STD 指令:将标志寄存器的DF位置1
­
PUSHF 和POPF
PUSHF 功能是将标志寄存器的值压栈,POPF是从栈中弹出数据,送入标志寄存器中
­
内中断的产生
条件:
(1) 除法错误,比如:DIV指令产生的除法溢出;
(2) 单步执行;
(3) 执行int0指令
(4) 执行int指令
CPU 用8位的中断类型码通过中断向量表(中断向量的列表)找到相应的中断处理程序的入口地址。
所谓中断向量,就是中断处理程序的入口地址
中断向量的表,就是中断处理程序的入口地址的列表
中断向量表在内存中保存,其中存放着256个中断源,所对应的中断处理程序的入口。
8086PC 机,中断向量表指定放在内存地址0处。从内存0000:0000到0000:03E8的1000个单元中存放着中断向量表。
­
中断向量表中,一个表项存放一个中断向量,也就是一个中断处理程序的入口地址,对于8086CPU,这个入口地址包括段地址和偏移地址,所以一个表项占两个字,高地址字存放段地址,低地址字存放偏移地址。
­
(1) (从中断信息中)取得中断类型码
(2) 标志寄存器的值入栈;(因为在中断过程中要改变标志寄存器的值,所以先将其保存在栈中)
(3) 设置标志寄存器的第8位TF和第9位IF的值为0;
(4)CS 的内容入栈
(5)IP 的内容入栈
(6) 从内存地址为中断类型码*4和*4+2的两个字单元中读取中断处理程序的入口地址设置IP和CS
简单描述:
(1) 取的中断类型码N;
(2)Pushf
(3)TF=0,IF=0
(4)Push CS
(5)PUSH IP
(6)(IP)=(N*4),(CS)=(N*4+2)
­
中断处理程序的编程方法:
(1) 保存用到的寄存器
(2) 处理中断
(3) 恢复用到的寄存器
(4) 用iRet指令返回
在中断过程中,寄存器入栈的顺序是标志寄存器,CS,IP,而IRET的出栈顺序是IP,CS,标志寄存器,刚好和其相对应,实现了用执行中断处理程序前的CPU现场恢复标志寄存器和CS,IP的工作
­
­
Int 指令:INT N
执行过程:
(1) 取中断类型码 N
(2) 标志寄存器入栈,IF=0;TF=0
(3)CS,IP 入栈
(4) (IP)=(n*4),(CS)=(n*4+2)
系统将一些具有一定功能的子程序,以中断处理程序的方式提供给应用程序调用,当然这些子程序也可以自己编写.
­
在系统板的ROM中存放着一套程序,称为BIOS(基本输入输出系统), BIOS主要包括:
(1) 硬件系统的检测和初始化程序
(2) 外部中断和内部中断的中断例程
(3) 用于对硬件设备进行I/O操作的中断例程
(4) 其他和硬件系统相关的中断例程
BIOS 和DOS提供的中断例程安装到内存中:
(1) 开机后,CPU加电,初始化(CS)=0FFFFH,(IP)=0,自动从FFFF:0单元开始执行程序。FFFF:0处有一条转跳指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序
(2) 初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。注意,对于BIOS所提供的中断例程,只需要入口地址登记在中断向量表中即可。因为它们是固化到ROM中的程序。一直在内存中存在
(3) 硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导,从此将计算机交有操作系统控制。
(4)DOS 启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。
­
在PC机系统中,和CPU通过总线相连的芯片除各种存储器外,还有以下3种芯片:
(1) 各种接口卡(比如:网卡,显卡)上的接口芯片,它们控制接口卡进行工作
(2) 主板上的接口芯片,CPU通过它们对部分外设进行访问
(3) 其他芯片,用来存储相关的系统信息,或进行相关的输入输出处理
这些芯片中,都有一组可以由CPU读写的寄存器,这些寄存器,他们在物理上可能处于不同的芯片中,但是它们有以下两点上相同:
(1) 都和CPU的总线相连,当然这种连接是通过它们所在的芯片进行的
(2)CPU 对它们进行读或写的时候都通过控制线向它们所在的芯片发出端口读写命令。
可见,从CPU的角度,将这些寄存器都当作端口,对它们进行统一编址,从而建立了一个统一的端口地址空间。每个端口在地址空间中都有一个地址。
CPU 可以直接读写3个地方的数据:
(1)CPU 内部的寄存器;
(2) 内存单元
(3) 端口
­
端口地址和内存地址一样,通过地址总线来传送,在PC系统中,CPU最多可以定位64K个不同的端口。则端口地址的范围是0-65535
端口的读写指令只有两条:in和out
在in,out指令中,只能使用AX或AL来存放从端口中读入的数据或要发送到端口中的数据,访问8位端口时用AL, 访问16位端口时用AX
对0-255以内的端口进行读写时
In al ,20h
Out 20h,al
对256-65535的端口进行读写时,端口号放在DX中
Mov dx,3f8h
In al,dx
Out dx,al
­
CMOS RAM
PC 机中,有一个CMOS RAM芯片,一般简称为CMOS。
(1) 包含一个实时钟和一个有128个存储单元的RAM存储器
(2) 该芯片靠电池供电
(3)128 个字节的RAM中,内部实时钟占用0-0dh单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时BIOS程序读取。BIOS也是提供了相关的程序,使我们可以在开机的时候配置CMOS RAM中的系统信息
(4) 该芯片内部有两个端口,端口地址为70h和71h.CPU通过这两端口在读写CMOS RAM
(5)70h 为地址端口,存放要访问的CMOS RAM单元的地址;71H为数据端口,存放从选定的CMOS RAM单元中读取数据,或要写入到其中的数据。可见,CPU对CMOS RAM的读写分两步进行,比如:读CMOS RAM的2号单元:
  * 将2送入端口70h
  * 从71h读出2号单元的内容
­
Shl 和shr 是逻辑依位指令,shl 是逻辑左移指令:
(1) 将一个寄存器或内存单元中的数据向左移位;
(2) 将最后移出的一位写入CF中
(3) 最低位用0补充
如果移动位数大于1时,必须将移动位数放在cl中
­
Shr 是逻辑右移指令,它和shl所进行的操作刚好相反:
(1) 将一个寄存器或内存单元中的数据想右移位;
(2) 将最后移出的一位写入CF中
(3) 最高位用0补充
­
如果移动位数大于1时,必须将移动位数放在cl中
­
CPU 除了有运算能力
还要有I/O能力
外设接口芯片的内部有若干寄存器,CPU将这些寄存器当作端口来访问
外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也不是直接送入外设,而是先送入端口中,在由相关的芯片送到外设。CPU还可以向外设输出控制命令,而这些控制命令也是先送到相关芯片的端口中,然后在由相关的芯片根据命令对外设实施控制。
­
PC 机系统中,外中断源一共有两类:
1 可屏蔽中断
2 不可屏蔽中断
(8086CPU,不可屏蔽中断类型码固定为2)
 
­
键盘扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60H
引发9号中断
当键盘的输入到达60H端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU检测到该中断信息后,如果IF=1, 则响应中断,引发中断过程,转去执行int 9中断例程
3 执行int9中断例程
BIOS 提供了int9中断例程,用来进行基本的键盘输入处理:
(1) 读出60H端口中的扫描码;
(2) 如果是字符键的扫描码,将该扫描码和它对应的字符码(即ASCII码)送入内存中的BIOS键盘缓冲区;如果是控制键(如CTRL)和切换键(如CapsLock)的扫描码,则将其转变为状态字节(用二进制位记录控制键和切换键状态的字节)写入内存中的存储状态字节的单元
(3) 对键盘系统进行相关的控制,如:向芯片发出应答信息
­
BIOS 键盘缓冲区是系统启动后,BIOS用于存放int9中断例程所接收的键盘输入的内存区,该内存区可以存储15个键盘输入,因为int9中断例程除了接收扫描码外,还要产生和扫描码对应的字符码,所以在BIOS键盘缓冲区中,一个键盘输入用一个字单元存放,高位字节存放扫描码,低位字节存放字符码
­
键盘输入的处理过程:
(1) 键盘产生扫描码;
(2) 扫描码送入60h端口;
(3) 引发9号中断;
(以上由硬件系统完成)
(4)CPU 执行int9中断例程处理键盘输入
­
指令系统总结:
* 数据传送指令:
比如:MOV,PUSH,POP,PUSHF,POPF,XCHG等都是数据传送指令,实现寄存器和内存,寄存器和寄存器之间的单个数据传送
* 算术运算指令
比如:ADD,SUB,ADC,SBB,INC,DEC,CMP,IMUL.IDIV,AAA等都是算术运算指令,实现寄存器和内存中的数据算数运算,它们执行结果影响标志寄存器的:SF,ZF,CF,PF,AF位
* 逻辑指令:
比如:AND,OR,NOT,XOR,TEST,SHL,SHR,SAL,SAR,ROL,ROR,RCL,RCR等,除了NOT指令外,它们都影响标志寄存器相关标志位
* 转移指令:
可以修改IP,或同时修改CS和IP的指令统称为转移指令,有以下几类:
(1) 无条件转移指令,比如:JMP
(2) 条件转移指令,比如:JCXZ,JE,JB,JA,JNB,JNA
(3) 循环指令:LOOP
(4) 过程:CALL,RET,RETF
(5) 中断:INT,IRET
* 处理机控制指令 :
这些指令对标志寄存器或其他处理机状态进行设置,比如:CLD,STD,CLI,STI,NOP,CLC,CMC,STC,HLT,WAIT,ESC,LOCK等都是处理机控制指令
* 串处理指令:
这些指令对内存中的批量数据进行处理:MOVSB,MOVSW,CMPS,SCAS,LODS,STOS等。若要使用这些指令方便地进行批量数据的处理,则需要和REP,REPE,REPNE等前缀指令配合使用.
­
BIOS 提供了int 16h中断例程。该中断例程中包括的一个最重要的功能是从键盘缓冲区中读取一个键盘输入,该功能的编号为0,下面的指令从键盘缓冲区读取一个键盘输入,并且将其从缓冲区中删除;
MOV AH ,0
Int  16H
结果(AH)=扫描码,(AL)=ASCII码
­
INT 16H 中断例程的0号功能,步骤:
(1) 检测键盘缓冲区中是否有数据;
(2) 没有则继续做第一步
(3) 读取缓冲区第一个字单元中的键盘输入
(4) 将一读取的键盘输入从缓冲区中删除
­
INT 9 和INT 16相互配合。
­
­
应用INT 13H中断例程对磁盘进行读写:(下面以3.5英寸软盘为例)
现常用的3.5寸软盘分为上下两面,每面有80个磁道,每个磁道又分为18个扇区,每个扇区的大小为512B。则:2面*80磁道*18扇区*512B=1440KB=1.44MB
磁盘的实际访问由磁盘控制器进行,只能以扇区为单位对磁盘进行读写,在读扇区的时候,要给出 面号,磁道号和扇区号。面号和磁道号从0开始,而扇区从1开始。
我们可通过调用BIOS中断例程(INT 13H)来访问磁盘
下面读取0面0道1扇区的内容到0:200
MOV AX,0
MOV ES,AX
MOV BX,200H ; 指向接收从扇区读入数据的内存
­
MOV AL,1 ; 读取的扇区
MOV CH,0 ; 磁道号
MOV CL,1; 扇区号
MOV DL,0; 驱动器号 软盘从0开始,0:软盘A,1:软盘B 硬盘从80H开始,80H硬盘C.81H:硬盘D
­
MOV DH,0 ; 磁头号 (对于软盘即面号,因为一个面用一个磁头来读写)
MOV AH,2 ;(AH)=INT 13H 的功能号(2表示读扇区)
INT 13H
­
返回参数:
操作成功:(AH)=0,(AL)=读入的扇区数
操作失败:(AH)=出错代码
­
将0:200中的内容写入0面0道1扇区
MOV AX,0
MOV ES,AX
MOV BX,200H
MOV  AL ,1 ; 写入的扇区数
MOV CH,0 ; 磁道号
MOV CL,1; 扇区号
MOV DL,0; ; 驱动器号
MOV DH,0; 磁头号(面)
MOV AH,3 ;INT 13H 功能号(3表示写扇区)
INT 13H
­
逻辑扇区号和物理扇区号的关系如下:
逻辑扇区号=(面号*80+磁道号)*18+扇区号-1
根据逻辑扇区号算出物理编号:
INT(): 取商;
REM(): 取余数.
面号=INT(逻辑扇区号/(1440))
磁道号=INT((REM(逻辑扇区号/1440))/18)
扇区号=REM((REM(逻辑扇区号/1440))/18)+1
­
( 摘抄)任何合理的学习过程(尽可能排除走弯路,盲目探索,不成系统)都是一个循序渐进的过程,我们必须通过易于全面把握的事物,来学习和探索一般的规律和方法。
信息技术是一个发展非常快,日新月异的技术,新的东西不断出现,使人在学习的时候往往无所适从,在你的身边不断有这样的故事出现:COOL先生用三天就学会了某中语言,并开始用它的编的软件,在这个故事的感召下,我们初学者也去尝试,但完全是另一种结果,COOL先生的快速学习只是露出水面的冰山一角,深藏水下的是他的较为系统的相关基础知识和相关的技术.......
补码(8位数据为例):先确定用00000000b-01111111b表示0-127,然后再用它们安位取反加1后的数据表示负数.
8 位补码表示的范围:-128-127
[1] 前转移
编译器中有一个地址计数器(AC),编译器在编译程序过程中,每读到一个字节AC就加一。当编译器遇到一些伪操作的时候,也会根据具体情况使AC增加,如DB,DW等
在向前转移时,编译器可以在读到标号S后记下AC的值AS,在读到JMP ...S后记下AC的值AJ,编译器可以用AS-AJ算出位移量DISP
JMP SHORT S 所对应的机器码格式为:EB DISP(占两个字节)
JMP NEAR PTR S 所对应的机器码格式为: E9 DISP(占3个字节)
JMP FAR PTR S 所对应的机器码格式为:EA 偏移地址:段地址(占5个字节)
[2] 后转移
编译器先读到JMP...S指令,由于它还没读到标号S,所以编译器此时还不能确定标号S 处的AC值,也就是说,编译器不能确定位移量DISP的大小,此时,编译器将JMP...S指令都当作JMP SHORT S来读取,记下JMP..S指令的位置和AC的值AJ,并作如下处理:
对于JMP SHORT S,编译器生成EB和1个NOP指令(相当于预留1个字节的空间,存放8位DISP)
对于JMP S和JMP NEAR PTR S,编译器生成EB和两个NOP指令(相当于预留2个字节的空间,存放16位DISP)
对于JMP FAR PTR S编译器生成 EB和4个NOP指令(相当于预留4个字节的空间,存放段地址和偏移地址)
以上处理后,编译器继续工作,当向后读到标号S时,记下AC的值AS,并计算出转移的位移量:DISP=AS-AJ.(END)

你可能感兴趣的:(汇编笔记)