测品娱乐
您的当前位置:首页汇编语言入门-高手经验

汇编语言入门-高手经验

来源:测品娱乐
汇编语言入门

三大类语言——汇编语言系列

汇编语言,总给人一中乱七八糟的东西整到一起,然后就出来了。事实上,汇编语言和此还真有点儿相像。

那什么是汇编语言呢?

计算机的编程语言经历了三大过程: 一、机器语言

计算机说白了就是对电信号的处理,计算机的电信号就是高电位和低电位两种,就是通和断。我们把通记作1,断记作0。所以,有人说计算机脑子笨,只会数到1。事实上,这已经足够了。最开始的编程可不像现在这么轻松。1001010101010000110就可能是一段指令(就是命令CPU做一个事情的最基本单元),但是,这实在是太费劲了。计算机读得懂,可人读不懂啊!

我真怀疑前辈是怎么熬过来的。

二、汇编语言

不知道那位天才的主意,他把这些难懂的计算机指令转换为通俗易懂的英语单词简写。比如说用的最多的10指令,它的作用就是把数据挪来挪去的,所以和英语单词move的意思差不多,干脆,把它替换成MOV吧

。这样,每个难懂的计算机指令都转换成为了指令

助记符(确实挺好记忆的)。然后,再由汇编器将汇编源代码翻译成机器语言。最开始的翻译就是一就是1,二就是2。现在的汇编器功能越来越全,以至于兼容了高级语言的语法,各种语法格式的汇编层出不穷,但是,最低级(这只是相对底层的说法)的还是Intel语法。 三、高级语言

虽然汇编语言令人轻松了不少,不过还是不接近人的思维。所以,高级语言又诞生了。比较有名的高级语言,比如C语言,就兼有高级低级两大特征。既有符合人类的思维方式,又可以和汇编语言进行轻松的转换,汇编味道还是很浓的。编译C语言有这么几个步骤:1、使用C编译器编译成汇编语言格式;2、使用汇编器编译成二进制可执行程序格式。所以,C语言一直是编写操作系统的首选语言(和汇编并列)。像VB这样的语言,就没有汇编味道了。

举个例子,下面是C语言的代码(我相信你学过C语言,如果没有学过,以后学吧 if(!a) return; //如果a等于0,就返回,否则a=1 a=1;

可以直接转化为汇编语言: cmp ax, 0 ;AX中是数据a

jnz nequ_zero ;如果不等于0就调到nequ_zero ret ;返回,相当于return

nequ_zero:

mov ax, 1 ;ax为1

怎么样,C语言是不是兼容高低两种风格?

):

我们已经初步地接触了一下汇编语言,感觉怎么样?看不懂?没关系,我们刚刚接触

它,还什么都没有学呢。大家只是先有一个感性的认识。好了,先写道这里吧!

CPU的寄存器——汇编语言入门

为什么不直接讲汇编语言,而先讲CPU寄存器呢?因为,汇编指令对它们的操作是最频繁的,如果不知道它们是干什么的话,怎么能学会汇编语言呢?

我们知道,数据交换方面,CPU内部数据交换最快,其次是内存,最慢的是什么光驱软驱硬盘什么的。在CPU中,就有一个个的小单元,用来暂时储存一些数据,就好像车站的寄存处一样,所以,它们有一个名称,叫CPU寄存器(简称寄存器)。这些寄存器都是:4个16位数据寄存器,2个16位指针寄存器,2个16位变址寄存器,2个16位控制寄存器,4个16位段寄存器。

一、通用寄存器:数据寄存器、指针寄存器、变址寄存器的总称。这些寄存器除了各自的用途外,都可以暂时存储数据、内存地址和运算结果。

1、数据寄存器:数据寄存器指AX、BX、CX和DX。这里的AH是AX的高字节,AL是AX的低字节(High和Low),其他的数据寄存器同理。这些数据寄存器的用途稍微有一点不同。

1)AX(Accumulator)寄存器,又叫累加器。用来存储乘法结果和除法结果,I/O数据。也可以用来做它用。同时,也通常进行加减法,所以叫做累加器。AX寄存器的使用频率最高,用途很广。

2)BX(Base)寄存器,又叫基地址寄存器(基址寄存器),用来存储内存地址。这是数据寄存器中唯一可用于存储器指针的寄存器。

3)CX(Counter)寄存器,又叫计数器。用来控制循环的次数。

4)DX(Data)寄存器,又叫数据寄存器,进行32位除法时,用来存放被除数的高16位和余数。也用作I/O端口地址。

2、指针寄存器和变址存储器:是指BP、SP、DI和SI,用来存储在段中的偏移地址(首次接触偏移地址,可能不太明白,不要紧,后面会讲的),我们把内存想象成一条街道,这条街道分成一部分一部分的(段),每部分的每家每户都有一个相对于这个部分开头的地址(偏移地址),比如你在平安街,平安街分为西平安街和东平安街,你家住在西平安街(段地址)31号(偏移地址)。

1)BP(Base)寄存器,又叫基地址指针寄存器。用来存储在段中的偏移地址。 2)SP(Stack)寄存器,又叫堆栈指针寄存器。这个寄存器有些特殊,因为它和堆栈紧紧相关。什么是堆栈呢,请看后面的段寄存器。

3)DI和SI寄存器,又叫目的地址寄存器和源地址寄存器。用来进行串操作。说一下串操作,假设把内存中一串连续的数据从这里挪到那里,怎么办?能够想到的是,把这一串连续的数据中第一个数据在内存中的地址(源地址)移到一个寄存器中(比如SI),然后把要到的地方在内存中的地址(目的地址)移到另一个寄存器中(比如DI)。然后把SI所指的数据挪到AX,再把AX中的数据挪到DI所指的地方。让SI和DI指向下一个数据。这种操作叫做串操作,就是把一串连续的数据挪到另一个连续的内存处。

二、控制寄存器,这些寄存器比较特殊,不能够存储数据。 1、IP寄存器,指向当前运行到的代码的内存偏移地址。

开始的时候,IP指向内存中的一个指令。然后,CPU根据IP中的内存地址,把这个指令读取进来,并执行。同时,IP指向下面的一个指令,就回到了步骤1,这样不断地执行下去,就是一步一步的。排除有指令缓存的情况。

2、标志寄存器:

有些指令会影响标志,有些指令不会影响标志,而有些指令受标志影响,有些指令不受标志影响。这些标志可以分为两组,一组主要受加减乘除运算影响,成为运算结果标志,另一些成为控制状态标志。

运算结果标志:

1)CF(Carry):进位标志,反应运算是否有进位和借位,有则为1,没有为0。有时作函数的出口参数。

2)ZF(Zero):零标志,运算结果为0则置位为1,运算结果不为零则复位为0。

3)SF(Sign):符号标志,反应运算结果的符号位。SF于运算结果的最高位(即符号位)相同。在80x86中,有符号数采用补码的形式表示,所以SF反映了运算结果的符号。如果运算结果为正,则SF为0,否则为1

4)OF(Overflow):溢出标志,用于反应有符号数运算是否引起溢出。如果运算结果超出了8位或16位有符号数的表示范围,即在字节运算时大于127或小于-128,字运算时大于32767或小于-32768,称为溢出,则OF被置1。

5)PF(Parity):奇偶标志,用于反应运算结果中“1”的个数,如果,“1”的个数为偶数,则PF置1,否则清0。

6)AF(Auxiliary Carry):辅助进位标志:在字节操作时,如发生低半字节向高半字节进位或借位;在字操作时,如发生低字节向高字节进位或借位,则AF被置1,否则清0。

2、状态控制标志

1)DF(Direction)方向标志,当DF为1时,串操作指令按递减方式改变有关存储器指针值;当DF为0时,串操作指令按递加方式改变有关寄存器值。设置DF方向为的指令为STD(Set Deriction),清除指令为CLD(Clean Direction)

2)IF(Interrupt)中断标志,当IF为1时,允许可屏蔽中断产生,当IF为0时,屏蔽任何可屏蔽中断。设置IF为1的指令是STI(Set Interrupt),设置IF为0的是CLI(Clean Interrupt)。

3)TF(Trap)追踪标志,当TF被置位1后,CPU进入单步方式。所谓单步方式,就是执行一条指令就产生一个单步中断,用于程序的调试。

三、段寄存器。这里应用了分段机制,80x86把一兆的内存(16位模式下只支持一兆)分为一个个的段,每个段寄存器就存储相应的段基地址。CS(Code Segment)代码段基址寄存器;DS(Data Segment)数据段基址寄存器;ES(Extra Segment)附加断寄存器;SS(Stack Segment)堆栈段寄存器。

至于分段机制的具体内容,将在以后的文章中介绍。

内存寻址和分段机制——汇编语言入门

上一篇文章介绍了CPU的寄存器,不知道大家留意到没有,这几个寄存器有一些特殊,SI/DI/SP/BP,这几个寄存器都有指针这个词,那什么是指针呢?CS/DS/ES/SS叫做段寄存器,什么又是段呢?为什么要出现分段机制?

一、什么是指针

内存,如果安装编程的眼光看的话,就是一连续的存储空间,这里,最小的存储空间是位(这个概念不用解释吧

),但是,位实在是太小了,所以,内存空间被分为1字节

1字节的,也就是把1字节作为一个单位。如果我们把内存空间比作一条街的话,这每一个单位就是一个楼。可是,我如何知道我需要的是哪个楼呢?我们知道,要找某一号楼的话,一般说这是XX街号楼,这叫地址。内存中每个单位也有一个地址,叫内存地址。内存地址是从0开始计数的。内存中第一个字节的内存地址是0x0000(这是十六进制

)什么

是十六进制,我就不再说明了。第二个字节的内存地址是0x0001。存储这些内存地址的寄

存器就叫指针寄存器,指针,就是指着这一个内存单元的“针”,说白了就是一个内存地址。

二、什么是分段机制

我们知道,16位的PC机上,内存寻址最远的是0xFFFF(1111111111111111),这是靠单一十六位寻址的最大范围了。但这实际上并不大,才能寻址到KB的地方,这实在是太小了。(怎么算的KB

)使用Windows自带的计算器,调整到科学型,选择[十六进

制],输入FFFF,然后加1,因为内存地址是从0算起的,得出的就是寻址的最远处,这时的数是10000,表示最远到0x10000字节处,不够直观,必须除以400(十六进制的),(我们知道,KB到B的换算是1024,十六进制的表示就是400)得到40(还是十六进制的),再选择十进制,就是,也就是KB。

确实太小了,怎么办呢?于是引入了段的概念,一个内存地址就由“段基址:段内偏移地址”表示。段基址,就是这个段的起始地址;段内偏移地址,就是距段基址的距离。这样,段内偏移地址最大是0xFFFF,所以,一个段的最大长度是KB。那怎么把这个内存地址换算成最基本的内存地址呢?规则是这样的:

实际内存地址=段基址×0x10+段内偏移地址

我们看一看,段基址最大是0xFFFF,段内偏移地址最大是0xFFFF,所以有: 0xFFFF×0x10+0xFFFF=0xFFFF0+0xFFFF=0x10FFEF 大约是1M,这可比KB大多了。

那么,一个内存地址就有两种表示方法了:0:0x1000=0x100:0

也就是说,段基址是0x0,段内偏移地址是0x1000,和段基址是0x100,段内偏移地址是0x0所指向的内存地址相同,不信你算一算。

你也许就知道了,CS/DS/ES/SS段寄存器存储的就是段基址。那么我们就可以用DS:0x0002得到数据段中偏移地址为0x0002的数据。

这四个段寄存器是各有分工的。在取指令时,自动把CS×0x10+IP得出要取的指令。在进行堆栈操作时,自动把SS×0x10+SP得到栈顶指针。在进行普通数据操作时,自动把

DS或ES乘以0x10+相应的偏移地址。所以,正常情况下,段基址可以省略。

三、“高高低低”原则

16位是2个字节,是1个字。一个字在内存中占用2个字节。规定:一个字存放到内存中时,低字节存放在地址较低的字节单元中,高字节存放在地址较高的字节单元中。

所以,0x1234存储中看起来像0x3412。 考考你

:0x12345678在内存中是怎么存储的?

四、内存寻址

既然要学习内存寻址,最好先了解一个最基本最常用的指令: mov 目的操作数,源操作数

这个指令就是把源操作数挪到目的操作数中。 1、立即寻址

立即寻址就是操作数就在指令中,是指令的一部分,存放在代码段中,这个操作数叫做立即数。立即数可以是8位的也可以是16位的。但是,16位的立即数要按照“高高低低”原则存储,即高位存放在高地址处,低位存放在低地址处。

例如指令:mov ax, 1234h

意思就是把0x1234挪到ax寄存器中。十六进制0x1234在指令中表示为1234h。

2、寄存器寻址

操作数就在CPU的寄存器中,指令中指定寄存器号。对于16位操作数,寄存器可以使ax,bx,cx,dx,si,di,sp和bp,对于8位操作数,寄存器可以使用ah,al,bh,bl,ch,cl,dh,dl。

例如,指令“mov bx,ax”和指令“mov ch,dl”中的源操作数和目的操作数都是寄存器寻址。 由于操作数在寄存器中,不需要访问存储器,所以这种寻址方法的指令执行速度较快。 3、直接寻址

操作数在内存中,指令直接包含操作数的有效地址。操作数一般存放在数据段中,所以操作数的地址由DS加上指令中的16位段内偏移地址得到。如果要访问其他的段中的数据,就要采用段超越前缀,即指定基地址寄存器不是DS的其他寄存器(CS,ES,SS),所以操作数可以不在数据段。

假设,DS的内容是0x1000,在段内偏移地址为0x1234的字存储单元中的内容是0x67,那么执行指令“mov ax,[1234h]”把ds段内的段偏移地址为0x1234中的字单元中的数据存放在ax中。这里的“[]”表示里面的数据是偏移地址。

下面的指令中的目的操作数采用了直接寻址,并使用了段超越前缀:

mov [es:1234h], al

它可以在整个k段中寻找操作数。直接寻址的操作数通常是程序使用的变量。 直接寻址的地址要放在方括号[]中。在源程序中,往往使用变量名表示。 4、寄存器间接寻址

操作数在内存中,操作数有效地址在si,di,bx,bp这四个寄存器之一中。一般情况下(即不使用段超越前缀),如果有效地址在si,di,bx中,则使用ds段寄存器中的数据为段基址;如果有效地址在bp中,则使用ss段寄存器、

例如:mov ax,[bx]

因为操作数在bx中,默认使用ds段寄存器。假设ds中的数据是0x1000,bx中的数据是0x1234,那么实际物理地址就是0x11234,假设这个字存储单元中的数据是0x5678,则执行指令之后,ax中的数据为0x5678。

使用段超越前缀:mov dh, es:[si]

这里,使用的段寄存器不再是ds,而是es。 使用段寄存器ss:mov [bp], cx

注意:寄存器名一定要放在方括号中。 mov [si], ax ;目的操作数寄存器间接寻址

mov si, ax ;目的操作数立即寻址(看看前面的) 5、寄存器相对寻址

这种寻址就稍微有点复杂

操作数在内存中,操作数的有效地址是一个基址寄存器(bx,bp)或变址寄存器(si,di)的内容加上指令中给定的8位或16位的位移量(就是偏移量)之和。

还是同样的道理,个例子就明白了:

mov ax, [si+1234h]

假设ds为0x1000,si为0x1111,则实际物理地址为0x1000×0x10+0x1111+0x1234=0x12345,如果0x12345中存储的字数据为0xffff,那么执行指令后ax中为0xffff。

6、基址加变址寻址

操作数还是在内存中,操作数的有效地址是由基址寄存器之一的内容加变址寄存器之一的内容相加得到的。

这好像不用说明了吧。还是同样的道理,si,di,bx引用ds段寄存器,bp引用ss段寄存器。这句话都说烦了。

si,di,bx引用ds段寄存器,bp引用ss段寄存器。比较难懂啊,举

例子:mov ax,[bx+di]

假设:ds=0x1000,bx=0x1234,di=0x12 那么实际物理地址为0x11246,假设字数据为0x115,那么执行后,ax中的数据为0x115。 下面两种方法是等价的: mov ax, [bx+di] mov ax, [bx][di]

7、相对基址加变址寻址

这个称呼真别扭,听着就吓唬人。事实上,一点儿也难。就是在基址加变址寻址的

基础上加上位移量。有点像寄存器相对寻址,不信往前看看。引用什么段寄存器我就不用说了(如果你还不知道……

举例:mov ax, [bx+di-2]

假设:ds=0x1111, bx=0x1234, di=0x4214

那么实际物理地址为0x16556,假设字数据为0x8847,那么执行后ax为0x8847。 尽管相对基址加变址寻址最复杂,却是最灵活的。下面四个表示方法均是等价的: mov ax, [bx+di+1234h] mov ax, 1234h[bx+di] mov ax, 1234h[bx][di] mov ax, 1234h[di][bx]

如果你留心的话,会发现bp指针寄存器引用的段寄存器始终默认是ss段寄存器。ss段寄存器就是堆栈段寄存器。什么是堆栈段呢?等待……

什么是堆栈——汇编语言入门

我们所接触到的段寄存器有四种:CS、DS、ES、SS,CS段是代码段,当然是存放代码的段了。DS和ES是存放数据的段。这个SS是堆栈段,什么是堆栈呢?堆栈又有什么用呢?

一、什么是堆栈

堆栈是一种线性表(

就是像一条线一样存储的序列),堆栈是一种的线性表。

堆栈只允许在一端进行插入和删除。允许插入和删除的一端称为栈顶(top),另一端称为栈底(button)。堆栈的插入叫做入栈,删除叫做出栈。根据堆栈的特点可知,最先入栈的总是最后出栈的,最后出栈的总是最先出栈的

ss段寄存器存储的是堆栈段的基地址,sp则存储堆栈段的栈顶。 注意!堆栈是向低地址生长的

为什么说栈底并不存在,假设现在sp指向栈底0x1003,如果再出栈(弹出一字节)的话,sp就会指向0x1004,这也可以。

二、堆栈操作

堆栈操作使用了两个指令:push入栈、pop出栈 1、push 操作数

将sp指向前一个字单元(或字节单元),并把操作数放在sp所指的字单元(或字节单元)中。

2、pop 操作数

将sp所指的字单元(或字节单元)中的数据放到操作数中,这时的操作数不能是立即数,只能是寄存器或内存地址,然后让sp指向下一个字单元(或字节单元)。

当然,也可以使用mov指令把sp所指向的数据挪到目的操作数中,只不过不改变sp的值。

现在假设堆栈为(b)的情况,sp指向0x1004,再假设0x1002中存储的数据为0x5555。问题:mov ax, [sp+2]之后,ax中的数据是什么?mov ax,[sp-2]之后,ax中的数据是什么?

sp+2指向0x1006(0x1004+0x2),所以ax中的数据是0x1234,同理sp-2指向0x1002,所以ax中的数据为0x5555。

三、堆栈的作用

这里只是简单的说明一下: 1、调用函数 2、暂时存储数据 3、保护寄存器数据

调用函数必然会有ip寄存器的变化,有时还需要存储参数,所以用到堆栈。有时为了保护一些暂时数据,使用堆栈无疑再好不过。为了防止函数改变寄存器的值,可以在进入函数时把寄存器入栈,离开函数时把寄存器出栈。

四、进出堆栈的顺序

切忌:先进后出,先出后进。

比如,要在某段指令前把ax和bx寄存器的值保护起来,就是压入堆栈,在这段指令之后再把它们恢复,看看下面的指令哪个对?

(a) push ax push bx

..... pop ax pop bx (b) push ax push bx ..... pop bx pop ax

(a)是错的,因为先进后出,ax先入栈,应该最后出栈,而(a)执行后,ax和bx的数据就会颠倒。bx后入栈,应该出栈,却存到了ax中,ax先入栈,应该后出栈,却存到了bx中。

事实上,使用这种方法交换两个寄存器的值也不是不行:push ax push bx pop ax pop bx

不过还有更好的方法,以后学习。

基本汇编指令知识——汇编语言入门

经过前面几篇文章的学习,基本了解了汇编语言的基础知识。下面,我们就要开始正式地接触汇编语言了。

首先,我们要了解汇编指令。 一、汇编语言指令分类

汇编语言的指令分为汇编指令、伪指令和宏指令。

汇编指令就是可以被汇编器直接翻译成二进制指令的指令。比如说我们最熟悉的指令mov,他就能够被直接翻译成二进制指令。

伪指令不能够被翻译成二进制指令,它像一个指挥员,指挥汇编编译器如何进行汇编,比如说各个段的指定,在数据段中初始化一个数据……

宏指令以后再说罢。

二、汇编语言指令格式 [标号:] 指令 [;注释] 注:[]括起来的是可省略的。

这是一条完整的汇编指令。标号代表这个指令的偏移地址,我们可以在其他指令中使用这个标号来代表这个偏移地址。指令就是要执行的指令,注释就是对这个指令的注解,在编译的时候注释就被全部删掉了,所以不会影响到最后的编译程序。

MOVEDATA: mov ax, 1 ;把1挪到ax寄存器中

……

mov bx, MOVEDATA ;把MOVEDATA标号处的便宜地址挪到bx寄存器中,

;相当于把MOVEDATA后面的指令的偏移地址挪到 ;bx中,我们不知道这个指令的偏移地址是什么。

伪指令的指令结构和指令语句一样,只不过标号后面的冒号省略。 [标号] 指令 [;注释] 三、指令语句分类

指令语句根据它们的作用分为以下类型: 指令类型 举例 数据传送指令 mov 堆栈操作指令 push,pop 标志操作指令 lahf 数算指令 add,div 逻辑运算指令 and,or,xor 位移指令 sal,shl 转移指令 jmp 串操作指令 rep

从下一篇开始,就要正式进入指令学习阶段了。Have a good time!

数据传送指令——汇编语言入门

1.传送指令

mov 目的操作数,源操作数

把源操作数指定的数据传送到目的操作数中去。源操作数和目的操作数可以是寄存器和内存地址(包括标号),源操作数还可以是立即数,目的操作数不可以。

mov ax, 0x1024 mov ax, [si] mov ax, [bp+2] mov ax, THATDATA 2.交换指令

xchg 操作数1,操作数2

把操作数1中的数据传送到操作数2中,把操作数2中的数据传送到操作数1中。操作数可以是寄存器和内存地址(包括标号),但不可以是立即数。

xchg bx, ax ;把ax和bx中的数据互换 3.端口操作指令 in 累加器, 端口地址 out 端口地址,累加器

当端口地址小于256时,可采用直接寻址方式,在指令中指定端口地址。如果端口地址大于等于256时,就要使用间接寻址方式,先将端口地址存放在dx中,然后操作。

in ax, 0x11f out 0x13, ax

mov dx, 0x1242 out dx, ax 4.取地址指令

lea 目的操作数, 源操作数

功能是取有效地址。源操作数必须是一个内存地址(或者标号),目的操作数必须是一个16位通用寄存器(8位的不行)。此指令将源操作数的地址偏移量送到目的操作数中。

lea bx, 0x1242 lea ax, 0x1246[bx][si] 5.32位传送指令

lds 通用寄存器,源操作数

将源操作数指定的4字节32位数据的高16位送入DS段寄存器中,低16位送到指定的通用寄存器中。

lds di, [bx]

6.32位地址传送指令 les 通用寄存器, 源操作数

将源操作数指定的连续四个存储单元中存放的32位内存地址指针(一个段地址和一个偏移地址),传送到指定的通用寄存器和段寄存器ES中。

les si, [bx][di]

堆栈指令和标志指令——汇编语言入门

1.入栈指令 push 操作数

把操作数放入堆栈中,操作数可以是立即数、寄存器、内存地址(或者标号)。 push 0x121 push ax push [si] 2.出栈操作 pop 操作数

把堆栈顶的数据弹出堆栈,放到操作数中,操作数不能是立即数。 pop ax pop bx 3.标志入栈操作 pushf

将标志寄存器入栈。 4.标志出栈操作 popf

把堆栈顶的数据弹出到标志寄存器中。 5.读取标志指令 lahf

把标志的低八位送入ah寄存器中。 6.设置标志指令 sahf

把ah寄存器中的数据送入标志的低八位中。

加减算术运算指令——汇编语言入门

1.加法指令

add 目的操作数,源操作数

源操作数和目的操作数相加,结果送目的操作数,并且影响标志位。

add ax, 1234h add cx, ax add BUF, ax add BUF, 14h

2.带进位加法指令

adc 目的操作数, 源操作数

带进位加法指令,用于多字节加法运算。两个操作数相加时,还要加上进位标志CF的当前值,结果送目的操作数。例如,有一个32位的数据已经存放在ax(高16位)和dx(低16位)中,现要加上一个常数0x123456:

add dx, 3456h ;存放数据低16位的寄存器dx和常数的低16位相加, ;如果有进位则CF置位1。

adc ax, 12h ;存放数据高16位的寄存器ax和常数的高16位相加。 3.自加运算 inc 操作数

把操作数加一后存放在操作数中。常用在循环结构中。

inc ax

4.BCD码加法调整

daa aaa

用于对BCD码加法的调整指令,要调整的结果存放在al中。DAA指令用于对组合BCD码相加的结果调整,AAA对非组合的BCD码调整。

mov al, 06h ;al=0x06

add al, 18h ;al=0x1e,即30

aaa ;al=24 5.减法指令

sub 目的操作数,源操作数

完成两个操作数的相减,结果在目的操作数中,影响标志位。 sub bx, ax sub [si+2], cl 6.带借位减法

sbb 目的操作数,源操作数

用于多字节减法指令,两操作数相减时,还要减去借位标志CF。比如,32位的数据高16位存放在ax中,低16位存放在dx中,现要减去0x123456:

sub dx, 3456h sbb ax, 12h 7.自减指令 dec 操作数

操作数减1,结果存放在操作数中。

dec cx

8.取反指令 neg 操作数

用来对有符号数进行操作。用0减去操作数,结果存操作数中。 9.比较指令

cmp 操作数1,操作数2

CMP的指令是把两数相减,只影响标志位,但结果不送操作数1。用来比较两数的大小。

当操作数1大于操作数2时,结果大于0,无借位,CF=0,ZF=0 当操作数1等于操作数2时,结果等于0,无借位,CF=0,ZF=1 当操作数1小于操作数2时,结果小于0,有借位,CF=1,ZF=0 10.BCD码减法调整指令

das aas

调整的结果在al中,das对组合bcd码相减的结果调整,aas对非组合的BCD码调整。

因篇幅问题不能全部显示,请点此查看更多更全内容