查看原文
其他

80x86 汇编语言基础知识

计算机与网络安全 计算机与网络安全 2022-06-01

一次性进群,长期免费索取教程,没有付费教程。

教程列表见微信公众号底部菜单

进微信群回复公众号:微信群;QQ群:16004488


微信公众号:计算机与网络安全

ID:Computer-network

汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地址符号(Symbol)或标号(Label)代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。普遍地说,特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。


许多汇编程序为程序开发、汇编控制、辅助调试提供了额外的支持机制。有的汇编语言编程工具经常会提供宏,它们也被称为宏汇编器。


汇编语言不像其他大多数的程序设计语言一样被广泛用于程序设计。在今天的实际应用中,它通常被应用在底层,硬件操作和高要求的程序优化的场合。驱动程序、嵌入式操作系统和实时运行程序都需要汇编语言


一、寄存器


寄存器是80x86平台下汇编语言的基本组成部分之一,是一种非常快速的存储器,通常用来保存量小且对速度有苛刻要求的数据。


1、什么是寄存器


寄存器是一个统称,但是一般情况下指的都是某一个寄存器,例如eax寄存器。但是eax寄存器又代表什么呢?可以说它本身什么也不代表,但是你可以赋予它代表任何事物的能力。其实这里我们所说的eax只不过是人们给它起的一个别名,就像是高级语言中的变量名一样,实质上它只是代表一段寄存器上一段4字节的固定区域,而eax其实就是这段固定区域起始地址的别名而已。


2、寄存器用来做什么


我们可以将寄存器看作是CPU提供给我们的变量名,可以用其保存任何我们想保存的数据,只不过它的数量很少且使用时有很多规定而已。


3、80x86 汇编语言中都有哪些寄存器


就80x86平台来说,其常用的寄存器共有28个,这28个寄存器的分布如图1所示。

图1  80x86寄存器

4、这些寄存器都是做什么用的


虽然从理论上来讲80x86的寄存器是可以随便使用的,但是Intel公司还是对其做了一个约定。在绝大多情况下程序员与编译器都会遵从这个约定,因此少数不遵从约定的程序按照其“违约”程度的不同从而对其稳定性的影响也不尽相同。


以下就是通常情况下各个通用寄存器的用途。


eax:扩展累加寄存器(在乘/除法中被主动调用),多数情况下可以用于其他用途。

ecx:循环计数器,多数情况下可以用于其他用途。

edx:数据寄存器,常用来存放8字长数据的高32位,多数情况下可以用于

ebx:基址寄存器,常用作存放存储器地址,多数情况下可以用于其他用途。

esp:指向堆栈(最上面一个栈帧的栈顶),绝大多数情况下不可以用于他用。

ebp:指向最上面一个栈帧的栈顶的底部,一般情况下不可以用于他用。

esi:扩展目的指针(由高速内存数据传送指令使用),多数情况下可以用于其他用途。

edi:同上。

eip:指令指针(存放下一条要执行的指令的地址),几乎不可以用于他用。


二、寻址模式


寻址模式(Addressing mode)是为了访问指令操作数而设置的特定于某种硬件的机制,80x86提供了3种不同的操作数,即寄存器操作数、立即操作数与内存操作数。表1描述了这些操作数所对应的寻址方式。

三、数据传输指令


数据传输指令是指将一段数据从一个地方传递到另一个地方,但是在80x86汇编中究竟可以怎样传递数据呢?以最常用的mov指令为例,图2很好地解答了这一问题。

图2  mov指令可操作的源数据与目的数据类型

1、mov指令


mov指令用于将数据从一个地方传递到另一个地方,且两个操作数中必须有一个是寄存器。


操作数个数:2。

指令原型:mov目标操作数,源操作数。

执行操作:目标操作数等于源操作数。

此指令在使用时有以下几点需要注意:

目的数可以是通用寄存器、存储单元和段寄存器(CS段寄存器除外)。

立即数不能直接送段寄存器。

不允许在两个存储单元之间传送数据。

不允许在两个段寄存器之间传送信息。


2、push入栈指令


push入栈指令用于将指定的数据压入堆栈,数据入栈时高位字节先入栈,低位字节后入栈。


操作数个数:1。

指令原型:push源操作数。

执行操作:将源操作数压入堆栈。


3、pop出栈指令


pop出栈指令用于将位于栈顶的数据弹出栈,数据弹出时低位字节先出栈,高位字节后出栈。


操作数个数:1。

指令原型:pop目标操作数。

执行操作:将栈顶的数据弹出,并保存在目标操作数中。


4、xchg交换指令


xchg是两个寄存器、寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同。


操作数个数:2。

指令原型:xchg目标操作数,源操作数。

执行操作:将目标操作数与源操作数的内容相交换。


5、lea有效地址传送指令


lea是微机8086/8088系列的一条指令,取自英语Load effect address。此指令的作用是计算源操作数的有效地址,并将它存储到目标操作数中。源操作数是使用处理器寻址模式之一指定的内存地址(偏移量部分);目标操作数是通用寄存器。


操作数个数:2。

指令原型:lea寄存器,源操作数。

执行操作:将源操作数的地址传送到目标操作数的寄存器中。


6、pushf标志进栈指令


将堆栈指针递减2,并将EFLAGS寄存器的低16位(即FLAGS寄存器)压入堆栈,将整个EFLAGS寄存器复制到堆栈时,不会复制VM与RF标志(位16与17)。


操作数个数:0。

指令原型:pushf。

执行操作:将标志寄存器的内容压入栈。


7、pope标志出栈指令


将栈顶的16位数据弹出,并将它存储到EFLAGS寄存器的低16位(即FLAGS寄存器),此指令执行pushf指令的逆操作。


操作数个数:0。

指令原型:popf。

执行操作:将栈顶的内容弹出到标志寄存器中。

四、算术运算与逻辑运算指令


算术运算与逻辑运算指令负责执行数学运算与逻辑运算功能,执行此类指令除了能得到相应的结果外,部分指令还会改变标志位,从而对控制转移类指令的执行产生影响,进而控制程序流程与逻辑。


1、add加法指令


将目标操作数与源操作数相加,结果存储到目标操作数。目标操作数可以是寄存器或内存位置,源操作数可以是立即数、寄存器或内存位置(但不能在一条指令中使用两个内存操作数)。


操作数个数:2。

指令原型:add目标操作数,源操作数。

执行操作:将源操作数与目标操作数相加,并将结果保存在目标操作数中。


2、adc带进位的加法指令


将目标操作数、源操作数以及进位(CF)标志相加,结果存储到目标操作数。目标操作数可以是寄存器或内存位置,源操作数可以是立即数、寄存器或内存位置(但不能在一条指令中使用两个内存操作数)。


操作数个数:2。

指令原型:adc目标操作数,源操作数。

执行操作:将源操作数、目标操作数以及进位(CF)标志相加,并将结果保存在目标操作数中。


3、inc加1指令


将目标操作数加1,同时保持CF标志的状态不变。目标操作数可以是寄存器或内存位置。


操作数个数:1。

指令原型:inc目标操作数。

执行操作:将目标操作数加1,同时保持CF标志的状态不变。


4、sub减法指令


将目标操作数减去源操作数,结果存储到目标操作数。目标操作数可以是寄存器或内存位置,源操作数可以是立即数、寄存器或内存位置(但不能在一条指令中使用两个内存操作数)。


操作数个数:2。

指令原型:sub目标操作数,源操作数。

执行操作:将目标操作数与源操作数相减,将结果保存到目标操作数。


5、sbb带借位的减法指令


将源操作数与进位(CF)标志相加,然后从目标操作数减去此结果。减法的结果存储到目标操作数。目标操作数可以是寄存器或内存位置,源操作数可以是立即数、寄存器或内存位置(不过,不能在一条指令中使用两个内存操作数)。


操作数个数:2。

指令原型:sbb目标操作数,源操作数。

执行操作:将源操作数与进位(CF)标志相加,然后从目标操作数减去此结果,将最终结果保存到目标操作数。


6、dec减1指令


将目标操作数减1,同时保持CF标志的状态不变,目标操作数可以是寄存器或内存位置。


操作数个数:1。

指令原型:dec目标操作数。

执行操作:将目标操作数减1,同时保持CF标志的状态不变。


7、mul无符号乘法指令


对目标操作数与源操作数执行无符号乘法,结果存储到目标操作数。目标操作数是位于AL、AX或EAX寄存器(取决于操作数的大小)中的隐式操作数,源操作数位于通用寄存器或内存位置。


操作数个数:2。

指令原型:mul源操作数。

执行操作:将目标操作数与源操作数执行无符号乘法,结果存储到目标操作数。目标操作数是位于al、ax或eax寄存器(取决于操作数的大小)中的隐式操作数,源操作数位于通用寄存器或内存位置。


8、imul有符号的乘法指令


对两个有符号操作数执行乘法。


操作数个数:1~3。

指令原型:imul目标操作数。

执行操作:对两个有符号操作数执行乘法。根据操作数的数量,此指令有3种形式。

单操作数形式。此形式与mul指令使用的形式完全相同,源操作数(位于通用寄存器或内存位置)乘以al、ax或eax寄存器(取决于操作数大小)中的值,乘积分别存储到ax、dx:ax或edx:eax寄存器。

双操作数形式。此种形式是目标操作数乘以源操作数,目标操作数是通用寄存器,源操作数可以是立即数、通用寄存器或内存位置,乘积存储到目标操作数位置。

三操作数形式。此种形式需要一个目标操作数与两个源操作数,第一个源操作数(可以是通用寄存器或内存位置)乘以第二个源操作数(立即数),乘积存储到目标操作数(通用寄存器)。


9、div无符号除法指令


将ax寄存器、dx:ax寄存器对或edx:eax寄存器对中的值(被除数)除以(无符号)源操作数(除数),结果存储到ax(ah:al)、dx:ax或edx:eax寄存器,源操作数可以是通用寄存器或内存位置。


操作数个数:2。

指令原型:div源操作数。

执行操作:将ax、dx:ax或edx:eax中的值(被除数)除以(无符号)源操作数(除数),结果存储到ax(ah:al)、dx:ax或edx:eax寄存器。


10、idiv有符号除法指令


将al、ax或eax寄存器中的值除以(有符号)源操作数,结果存储到ax、dx:ax或edx:eax寄存器。源操作数可以是通用寄存器或内存位置。


操作数个数:2。

指令原型:idiv源操作数。

执行操作:将al、ax或eax寄存器中的值除以(有符号)源操作数,结果存储到ax、dx:ax或edx:eax寄存器。


11、cmp比较指令


比较第一个源操作数与第二个源操作数,并根据结果设置EFLAGS寄存器中的状态标志。比较操作通过将第一个源操作数减去第二个源操作数来实现,然后按照与SUB指令相同的方式设置状态标志。将立即数用作操作数时,会按照符号扩展方式将它扩展到第一个源操作数的长度。


操作数个数:2。

指令原型:cmp源操作数,源操作数。

执行操作:比较第一个源操作数与第二个源操作数,并根据结果设置EFLAGS寄存器中的状态标志。


12、and逻辑与指令


在目标(第一个)与源(第二个)操作数上执行位“与”运算,结果存储到目标操作数位置。源操作数可以是立即数、寄存器或内存位置,目标操作数可以是寄存器或内存位置。


操作数个数:2。

指令原型:and目标操作数,源操作数。

执行操作:将目标操作数与源操作数进行逐位“与”运算,结果存储到目标操作数位置。


13、or逻辑或指令


在目标操作数与源操作数之间执行逐位“或”操作,结果存储到目标操作数位置。源操作数可以是立即数、寄存器或内存位置;目标操作数可以是寄存器或内存位置(但不能在一条指令中使用两个内存操作数)。


操作数个数:2。

指令原型:or目标操作数,源操作数。

执行操作:将目标操作数与源操作数进行逐位“或”操作,结果存储到目标操作数位置。


14、xor逻辑异或指令


对目标操作数与源操作数执行逐位“异或”运算,结果存储到目标操作数位置。源操作数可以是立即数、寄存器或内存位置,目标操作数可以是寄存器或内存位置(但不能在一条指令中使用两个内存操作数)。


操作数个数:2。

指令原型:xor目标操作数,源操作数。

执行操作:将目标操作数与源操作数进行逐位“异或”(xor)操作,结果存储到目标操作数位置。


15、not逻辑非指令


对目标操作数执行逐位“非”操作(将1改为0,将0改为1),结果存储到目标操作数位置,目标操作数可以是寄存器或内存位置。


操作数个数:1。

指令原型:not目标操作数。

执行操作:对目标操作数执行逐位“非”操作(每个1设置为0,每个0设置为1),结果存储到目标操作数位置。


16、test逻辑比较指令


将第一个源操作数与第二个源操作数的逐位逻辑“与”,根据结果设置SF、ZF及PF状态标志,然后丢弃结果。


操作数个数:2。

指令原型:test源操作数,源操作数。

执行操作:第一个源操作数与第二个源操作数进行逐位逻辑“与”,并根据结果设置SF、ZF及PF状态标志,然后丢弃结果。


五、串操作指令


串操作指令用于操作某一内存区域中由相同类型数据构成的一个整体(相当于一个数组),这种结构一般被用于保存字符串或其他连续存放的单一类型数据。


1、movs串传送指令


将源操作数指定的字节、字或双字移到目标操作数指定的位置。源操作数与目标操作数都是内存位置。源操作数的地址从ds:esi或ds:si寄存器中读取(具体取决于指令的地址大小属性,分别为32或16);目标操作数的地址从es:edi或es:di寄存器中读取(具体也取决于指令的地址大小属性)。


操作数个数:2。

指令原型:movs目标操作数,源操作数。

执行操作:将源操作数指定的字节、字或双字移到目标操作数指定的位置。


2、stos存入串指令


将al、ax或eax寄存器中的字节、字或双字分别存储到目标操作数。目标操作数是内存位置,其地址从es:edi或es:di寄存器读取(具体取决于指令的地址大小属性,分别是32或16)。


操作数个数:1。

指令原型:stos目标操作数。

执行操作:将al、ax或eax寄存器中的字节、字或双字存储到目标操作数。


3、lods取出串指令


将源操作数中的字节、字或双字分别加载到al、ax或eax寄存器。源操作数是内存位置,其地址从ds:edi或ds:si寄存器中读取(具体取决于指令的地址大小属性)。


操作数个数:1。

指令原型:lods源操作数。

执行操作:将源操作数中的字节、字或双字分别加载到al、ax或eax寄存器。


4、cmps串比较指令


比较第一个源操作数指定的字节、字或双字与第二个源操作数指定的字节、字或双字,并根据结果设置EFLAGS寄存器中的状态标志。两个源操作数都位于内存,第一个源操作数的地址从ds:esi或ds:si寄存器中读取(具体取决于指令的地址大小属性),第二个源操作数的地址从es:edi或es:di寄存器中读取(具体也取决于指令的地址大小属性)。


操作数个数:2。

指令原型:cmps源操作数,源操作数。

执行操作:比较第一个源操作数指定的字节、字或双字与第二个源操作数指定的字节、字或双字,并根据结果设置EFLAGS寄存器中的状态标志。


5、rep重复操作前缀


按计数寄存器(E)cx中指定的次数重复执行字符串指令,或重复到ZF标志不再满足指定的条件。


操作数个数:0。

指令原型:rep。

执行操作:按计数寄存器(E)cx中指定的次数重复执行字符串指令,或重复到ZF标志不再满足指定的条件为止。


六、控制转移指令


控制转移指令负责控制程序执行流程,它们一般会导致当前指令的执行轨迹发生改变,或执行调用子程序的功能。


1、jmp无条件转移指令


将程序控制权转移到指令流中的另一个点,不记录返回信息。


操作数个数:1。

指令原型:jmp目标操作数。

执行操作:将程序控制权转移到指令流中的另一个点,不记录返回信息。目标操作数指定要跳转到的指令地址,此操作数可以是立即数、通用寄存器或内存位置。


2、jcc有条件转移指令


检查EFLAGS寄存器中一个或多个状态标志(CF、OF、PF、SF及ZF)的状态,如果标志处于指定的状态(条件),则跳转到目标操作数指定的目标指令。


操作数个数:1。

指令原型:jcc目标操作数。

执行操作:这代表的一类指令的集合,jcc后面的cc可以替换成任何字符以使其组合成常见的跳转指令(如jne、je、jnc、jpe等)。此类指令根据判定条件的不同检查EFLAGS寄存器中一个或多个状态标志(CF、OF、PF、SF及ZF)的状态,如果标志处于指定的状态(条件),则跳转到目标操作数指定的地址。


3、loop循环指令


将ecx或cx寄存器用作计数器,执行循环操作。loop指令每执行一次,计数寄存器递减,然后检查是否为0。如果计数为0,则终止循环,并继续执行程序中loop指令后面的指令。如果计数器不为零,则执行近跳转,跳转到目标操作数,假定它是位于循环开头的指令。


操作数个数:0。

指令原型:loop。

执行操作:将ecx或cx寄存器用作计数器,执行循环操作。loop指令每执行一次,计数寄存器递减,然后检查是否为0,如果计数为0,则终止循环,并继续执行程序中loop指令后面的指令。


4、call函数调用指令


将函数返回信息保存到堆栈上,并跳转到目标操作数指定的函数地址执行。目标操作数指定被调用过程中第一条指令的地址,此操作数可以是立即数、通用寄存器或内存位置。


操作数个数:1。

指令原型:call目标操作数。

执行操作:将函数返回信息保存到堆栈上,并跳转到目标操作数指定的函数地址执行。


5、ret返回指令


将程序控制权转移到位于栈顶的返回地址。此地址通常由call指令放入堆栈,返回目标是call指令的下一条指令。


操作数个数:0。

指令原型:ret。

执行操作:将程序控制权转移到位于栈顶的返回地址。


七、处理器控制指令


处理器控制指令用于控制当前的处理器状态,这些指令可以控制处理器的暂停、等待、交权等各项工作。


1、clc进位置0指令


操作数个数:0。

指令原型:clc。

执行操作:清除EFLAGS寄存器中的CF标志。


2、cmc进位求反指令


操作数个数:0。

指令原型:cmc。

执行操作:对EFLAGS寄存器中的CF标志求补。


3、stc进位置1指令


操作数个数:0。

指令原型:stc。

执行操作:设置EFLAGS寄存器中的CF标志。


4、nop无操作指令


不执行操作。此指令是单字节指令,会占用指令流空间,但不会影响机器上下文(EIP寄存器除外)。


操作数个数:0。

指令原型:nop。

执行操作:不执行任何操作。


5、hlt停机指令


停止指令执行,并使处理器进入“暂停”状态。启用的中断、NMI或复位都会恢复执行。


操作数个数:0。

指令原型:hlt。

执行操作:停止指令执行,并使处理器进入“暂停”状态。

微信公众号:计算机与网络安全

ID:Computer-network

【推荐书籍】

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存