汇编入门(7 讲)
时间:2009-5-16 8:12:26
核心提示:第 5 章微机CPU 的指令系统指令系统确定了CPU 所能完成的功能,是用
汇编语言进行程序设计的最基本部分。如果不熟悉汇编指令的功能及其有关规定,那么,肯 定不能灵活运用汇编语言。所以,本章的内容是学习本课程的重点和难点。5.1 汇编语言 指令格式为了介绍指令系统中指令的功能,先要清楚汇编语言是如何书写指令的... 第5章微机CPU的指令系统
指令系统确定了CPU 所能完成的功能,是用汇编语言进行程序设计的最基本部分。如
果不熟悉汇编指令的功能及其有关规定,那么,肯定不能灵活运用汇编语言。所以,本章的 内容是学习本课程的重点和难点。 5.1 汇编语言指令格式
为了介绍指令系统中指令的功能,先要清楚汇编语言是如何书写指令的,这就象在学习 高级语言程序设计时,要清楚高级语言语句的语义、语法及其相关规定一样。 5.1.1 指令格式
汇编语言的指令格式如下:
指令助忆符 [ 操作数1 [, 操作数2 [, 操作数3]]] [; 注释]
指令助忆符体现该指令的功能,它对应一条二进制编码的机器指令。指令的操作数个数 由该指令的确定,可以没有操作数,也可以有一个、二个或三个操作数。绝大多数指令的操 作数要显式的写出来,但也有指令的操作数是隐含的,不需要在指令中写出。 当指令含有操作数,并要求在指令中显式地写出来时,则在书写时必须遵守: 指令助忆符和操作数之间要有分隔符,分隔符可以是若干个空格或TAB 键; 如果指令含有多个操作数,那么,操作数之间要用逗号\,\分开。 指令后面还可以书写注释内容,不过,要在注释之前书写分号\;\。 5.1.2了解指令的几个方面
在学习汇编指令时,指令的功能无疑是我们学习和掌握的重点,但要准确、有效地运用 这些指令,我们还要熟悉系统对每条指令的一些规定或约束。 归纳起来,对指令还要掌握以下几个方面内容: 、要求指令操作数的寻址方式;
、指令对标志位的影响、标志位对指令的影响;
、指令的执行时间,对可完成同样功能的指令,要选用执行时间短的指令(见附 录2 )。
5.2、指令系统
指令系统是CPU 指令的集合,CPU 除了具有计算功能的指令外,还有实现其它功能的 指令,也有为某种特殊的应用而增设的指令。 通常,把指令按其功能分成以下几大类: 数据传送指令 标志位操作指令 算术运算指令 逻辑运算指令 移位操作指令 位操作指令 比较运算指令
下面,我们逐一介绍每类指令中 的指令。 ?循环指令 ?转移指令
?条件设置字节指令 ?字符串操作指令
? ASCII-BCD 码运算调整指令 ?处理器指令
5.2.1 数据传送指令
数据传送指令又分为:传送指令、交换指令、地址传送指令、堆栈操作指令、转换指令 和I/O 指令等。
除了标志位操作指令SAHF 和POPF 指令外,本类的其它指令都不影响标志位。 1 、传送指令MOV(Move Instruction)
传送指令是使用最频繁的指令,它相对于高级语言里的赋值语句。指令的格式如下: MOV Reg/Mem, Reg/Mem/Imm
其中:Reg—Register(寄存器),Mem—Memory(存储器),Imm—Immediate( 立即数),它 们可以是8 位、16 位或32 位( 特别指出其位数的除外) 。在本网络课件的网页中,都将采用上
述缩写,此后不再说明。
指令的功能是把源操作数(第二操作数)的值传给目的操作数(第一操作数)。指令执行后, 目的操作数的值被改变,而源操作数的值不变。在存储单元是该指令的一个操作数时,该操 作数的寻址方式可以是任意一种存储单元寻址方式。 下面列举几组正确的指令例子: 源操作数是寄存器
MOV CH, AL MOV BP, SP MOV ECX, EBX MOV DS, AX MOV [BX], CH MOV [BX+SI], AX
源操作数是存储单元
MOV AL, [100H] MOV BX, ES:[DI] MOV EDX, [BX]
MOV BX, VARW MOV AX, [BX+SI] MOV CH, [BX+DI+100H]
其中:VA R W 是字类型内存变量(下同)。 源操作数是立即数
MOV AL, 89H MOV BX, -100H MOV EDX, 12345678H MOV VARW, 200H MOV [BX], 2345H MOV [BX+DI], 1234H
在汇编语言中,主要的数据传送方式如图5.1所示。虽然一条 MOV指令能实现其中大 多数的数据传送方式,但也存在MOV指令不能实现的传送方式。
对MOV指令有以下几条具体规定,其中有些规定对其它指令也同样有效。
1) 、两个操作数的数据类型要相同,要同为8 位、16位或32位;如:MOV BL, AX等是 不正确的;
2) 、两个操作数不能同时为段寄存器,如:MOV ES, DS等;
3) 、代码段寄存器 CS不能为目的操作数,但可作为源操作数,如:指令 MOV CS, AX
等不正确,但指令MOV AX, CS等是正确的;
4) 、立即数不能直接传给段寄存器,如:MOV DS, 100H等; 5) 、立即数不能作为目的操作数,如:MOV 100H, AX等; 6) 、指令指针IP ,不能作为MOV指令的操作数;
7) 、两个操作数不能同时为存储单元,如:M O V VA R A , VA R B等,其中VA R A 和VA R B
是同数据类型的内存变量。
对于规定2 、4 和7 ,我们可以用通用寄存器作为中转来达到最终目的。表5.1列举一个可
行的解决方案,尽供参考。读者可考虑用其它办法来完成同样的功能。 表5.1 MOV 指令的变通方法
功能描述不正确的指令可选的解决方法
把DS的值传送给ES MOV ES, DS MOV AX, DS MOV ES, AX
把100H传给DS MOV DS, 100H MOV AX, 100H MOV DS, AX
把字变量VA R B 的值传送 给字变量VA R A
MOV VARA, VARB MOV AX, VARB MOV VARA, AX
对于情况1 :不同位数数据之间的传送问题,在80386 及其以后的 CPU 中,增加一组新 的指令——传送-填充指令,它可把位数少的源操作数传送给位数多的目的操作数,多出的 部分按指令的规定进行填充。
2 、传送—填充指令(Move-and-Fill Instruction)
传送—填充指令是把位数短的源操作数传送给位数长的目的操作数。指令格式如下: MOVSX/MOVZX Reg/Mem, Reg/Mem/Imm ;80386+
其中:80386+表示80386及其之后的CPU ,其它类似符号含义类同,不再说明。
指令的主要功能和限制与MOV指令类似,不同之处是:在传送时,对目的操作数的高 位进行填充。根据其填充方式,又分为:符号填充和零填充。 传送—填充指令的功能如图5.2所示。
、符号填充指令MOVSX(Move with Sign-Extend)
MOVSX的填充方式是:用源操作数的符号位来填充目的操作数的高位数据位。 、零填充指令MOVZX(Move with Zero-Extend)
MOVZX 的填充方式是:恒用0 来填充目的操作数的高位数据位。
例5.1 已知:AL=87H,指令 MOVSX CX, AL ,MOVZX DX, AL执行后,问CX和DX 的值是什么?
解:根据传送-填充指令的填充方式可知:
指令MOVSX CX, AL 执行后,(CX)=0FF87H ,指令MOVZX DX, AL 执行后, (DX)=0087H 。
从上例可看出,两条指令的源操作数完全一样,但因为它们的填充方式不同,所得到的 结果而就不同。
试比较下列指令,分析它们执行结果的相同和不同之处: MOV AX, 87H MOVSX AX, 87H MOVZX AX, 87H 3 、交换指令XCHG(Exchange Instruction)
交换指令XCHG 是两个寄存器,寄存器和内存变 量之间内容的交换指令,两个操作数的数据类型要相 同。其指令格式如下:
XCHG Reg/Mem, Reg/Mem
该指令的功能和MOV指令不同,后者是一个操作
数的内容被修改,而前者是两个操作数都会发生改变。 寄存器不能是段寄存器,两个操作数也不能同时为内存 变量。
XCHG 指令的功能如图5.3所示。
例5.2 已知:AX=5678H ,BX=1234H ,指令 XCHG AX, BX执行后,AX和BX的值是什 么?
解:这是两个寄存器内容进行交换,指令执行后,有:(AX)=1234H ,(BX)=5678H 。
4 、取有效地址指令LEA(Load Effective Address)
指令LEA 是把一个内存变量的有效地址送给指定的寄存 器。其指令格式如下: LEA Reg, Mem
该指令通常用来对指针或变址寄存器BX、DI或SI 等置初 值之用。其功能如右图所示。 例如:
? BUFF ER
DB 100 DUP(?) ?
LEA BX, BUFFER ; 把字节变量BUFFER 在数据段内的偏移量送给BX ?
问题:指令“LEA BX BUFFER”和“MOV BX, OFFSET BUFFER”的执行效果是一样的 吗?指令“LEA BX,[BX+200]”和“MOV BX,OFFSET [BX+200]”二者都正确吗? 5 、取段寄存器指令(Load Segment Instruction)
该组指令的功能是把内存单元的一个“低字”传送给指令中指定的16位寄存器,把随后的 一个“高字”传给相应的段寄存器(DS 、ES、FS、GS和SS)。其指令格式如下: LDS/LES/LFS/LGS/LSS Reg, Mem
指令LDS(Load Data Segment Register)和LES (Load Extra Segment Register) 在8086CPU 中就存在,而LFS 和LGS(Load Extra Segment Register)、LSS (Load Stack Segment Register) 是80386及其以后 CPU 中才有的指令。
若Reg 是16 位寄存器,那么,Men 必须是32位指针;若 Reg 是32 位寄存器,那么,Men
必须是48位指针,其低32 位给指令中指定的寄存器,高16位给指令中的段寄存器。指令的执
行结果如图5.5所示。
例如: ?
POINTER DD 12345678H ?
LDS BX, POINTER
?
指令的执行结果如图5.5所示。各寄存器的内容分别为:(BX)=5678H ,(DS)=1234H。 下面控件是学习和掌握MOV、MOVSX/MOVZX、XCHG 、LEA 、LDS/LES/LFS/LGS/LSS 指令的,它可检查用户输入这些指令的合法性,并对合法的指令显示其执行的结果。 注意:如果指令中含有表示内存单元的寻址方式,那么其控件中的\内存单元的类型\即表示该指令中内存单元的数据类型。
6 、堆栈操作指令(Stack Operation Instruction)
堆栈是一个重要的数据结构,它具有“先进后出”的特点,通常用来保存程序的返回地址。 它主要有两大类操作:进栈操作和出栈操作。 1) 、进栈操作
、PUSH(Push Word or Doubleword onto Stack) 指令格式:PUSH Reg/Mem PUSH Imm ;80286+
一个字进栈,系统自动完成两步操作:SP←SP-2 ,(SP) ←操作数;
一个双字进栈,系统自动完成两步操作:ESP ←ESP-4,(ESP) ←操作数。 、PUSHA(Push All General Registers) 指令格式:PUSHA ;80286+
其功能是依次把寄存器AX、CX、DX、BX、SP、BP、SI 和DI等压栈。 、PUSHAD(Push All 32-bit General Registers) 指令格式:PUSHAD ;80386+
其功能是把寄存器EAX、ECX、EDX、EBX、ESP 、EBP 、ESI 和EDI 等压栈。 2) 、出栈操作
、POP(Pop Word or Doubleword off Stack)