本文主要是介绍汇编语言基础--汇编操作指令概述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文是接续"汇编语言基础--机器级数据存储",主要介绍汇编指令的构造、寻址和指令主要分类。
操作指令
指令的基本要素:
在"计算机处理器(CPU)基础"介绍了一条完整可执行指令包括指令码和操作数。由于同一功能的指令要处理不同数据类型的操作数,这样指令的长度判读、计算的复杂度等存在差别,所以即使是同一功能的指令也存在不同的版本和编码。如针对不同数据类型,mov(传送数据)指令,有movb(传送字节),movw(传送字),movl(传送双字)三种不同的版本(这里都是基于AT&T的GAS)。
指令寻址:
指令中存在三种寻址方式,使用立即数、寄存器和储存器引用,GAS汇编代码书写有特殊的方法区分这三种寻址方式。立即数是直接存储在完整指令代码中的数据,如movl $0x1a, %eax,这里就是将16进制的1a存储到eax寄存器中(GAS要求立即数前需要有$, 寄存器前有%)。movl $0x1a, %eax 语句中的%eax就是寄存寻址,意味着会使用该寄存器中的值或者是将某个值存储到寄存器中。
存储器寻址是指读取存储器中某个位置上值或者将某个值存储在存储器中的某个位置。存储器寻址又包括多种寻址方式。
1.绝对寻址:GAS中书写汇编代码时,常数前没有$符号时,如movl 0x104, %eax,这里就不是讲0x104移动到eax寄存器中,而是指将存储器绝对地址0x104中的值移动到eax寄存器中
2.间接寻址:使用寄存器中存储的值作为存储器的地址读取或者写入数据。书写时只需要加上括号即可,如movl $20, (%esp), 这里代表将立即数存储在存储地址为寄存器esp中值的存储器位置中。
3.基址+偏移量寻址:寄存器中存储的值作为基地址,立即数作为基地址的偏移量,两者的和作为存储器地址。书写方式是在间接寻址的书写寄存上,括号前写上常数偏移量。如movl $20, -3(%esp),是将立即数20存储在%esp-3的存储器位置。
4.一般化的变址寻址(加上伸缩因子):变址寻址的不同之处在于,取两个寄存器,一个作为基址寄存器,另一个作为变址寄存器,一个常数作为伸缩因子,一个立即数作为偏移,内存地址的确定由基址+变址与伸缩因子的积+偏移。书写方式如9(%eax ,%edx ,4),9位偏移量,4为伸缩因子。其中不同部分可以为空,构成不同类型的变址。
tips:这里所指的内存地址是指地址空间的地址,使用虚拟内存的机制,实际访问内存时,还会有一步转换为物理地址,一般由MMU按照TLB或者内存中页表的映射转换为物理地址,从内存中取出数据。
指令分类:
指令系统中,主要有四种类型的指令,分别是数据传输指令、算数与逻辑操作、控制指令和转移指令。
1.数据传输指令
数据传输指令主要用来实现数据的移动。参考指令有:
指令 | 效果 | 描述 |
movl S, D | D <- S | 传送双字 |
movw S, D | D <- S | 传送字 |
movb S, D | D <- S | 传送字节 |
movsbl S, D | D <- 符号扩展 | 传送字节,符号扩展为双字 |
movzbl S, D | D <- 零扩展 | 传送字节,零扩展为双字 |
pushl S | R[%esp] <- R[%esp]-4 M[R[%esp]] <- S | 压栈 |
popl D | D <- M[R[%esp]]; R[%esp] <- R[%esp]+4 | 出栈 |
2.算数和逻辑操作(注意这些指令都存在w和b版本)
这类操作符主要用来实现算数与逻辑运算。参考指令有:
指令 | 效果 | 描述 | |
计算有效地址 | leal S, D | D <- &S | 将S的地址移动到D中(movl是将S地址中的值移动到D中) |
一元操作符 | incl D decl D negl D notl D | D <- D+1 D <- D-1 D <- -D D <- ~D | 加一 减一 取负 去补 |
二元操作符 | addl S, D subl S, D imull S, D xorl S, D orl S, D andl S, D | D <- D + S D <- D - S D <- D*S D <- D^S D <- D|S D <- D&S | 加 减 乘 异或 与 |
移位操作 | sall k, D shll k, D sarl k, D shrl k, D | D <- D<<k D <- D<<k D <- D>>k D <- D>>>k | 左移 左移 算数右移 逻辑右移 |
特殊操作 | imull S
mull S
cltd S
idivl S
divl S | R[%edx]:R[%eax] <- SxR[%eax] R[%edx]:R[%eax] <- SxR[%eax] R[%edx]:R[%eax] <- R[%eax] R[%edx] <- R[%edx]:R[%eax] mod S R[%eax] <- R[%edx]:R[%eax] / S R[%edx] <- R[%edx]:R[%eax] mod S R[%eax] <- R[%edx]:R[%eax] / S | 有符号全64位乘法 无符号全64位乘法 符号扩展转换为64位 有符号除法 (两步是同时,eax没变) 无符号除法 |
3.控制指令
通过条件码(psw程序状态字)和跳转指令实现if...else和循环。
A.程序状态字
可以参考8086的程序状态字,如图:
绿色是三个控制标志位,控制cpu的操作:
DF:derection flag, 方向标志位,它指定字符串处理的方向,当该标志为1时,字符串以递减顺序处理,即由高字位向低字位处理,反之,则递增顺序处理。
IF:Interrupt enable flag, 它指定cpu能否响应外部中断请求,如果为1,则接受外部中断请求,否则,则不接受。
TF:trap flag,跟踪标志位,是为程序调试设置的陷阱控制位,当为1时,cpu处于单步状态,每执行一条指令,就会产生一个内部中断,复位时则cpu正常工作。
黄色是六个状态标志位:
OF: overflow flag, 当补码运算有溢出时,OF=1,否则,OF=0。
SF:sign flag, 符号标志位,为1时表示最近的运算结果为负数。
ZF:zore flag, 零标志位,若当前结果是0,则ZF等于1,否则为0。
CF: carry flag, 进位标志位,无符号数运算产生溢出时,设置为1,否则设置为0,。
AF: Auxiliary cary flag, 辅助进位标识位.
PF:Parity Flag, 辅助进位标志位。
B.会设置条件码的指令:
1.上面提到的运算指令。
2.比较指令
指令 | 效果 | 描述 |
coml(comb, comw) S2, S1 | S1 - S2 | 比较字节(相等,零标志位设置1,其他标志大小可以判断大小关系) |
testl(testb, testw) S2, S1 | S1&S2 | 测试字节(通过与运算来设置零标志位或者负数标志位) |
C.会访问条件码的指令
(1).根据条件码设置值
指令 | 同义指令 | 效果 | 设置条件 |
sete D
setne D
| setz
setnz
| D <- ZF
D <- ~ZF
| 相等/零
不等/非零 |
sets D
setns D
|
| D <- SF
D <- ~SF
| 负数
非负数 |
setg D
setge D
setl D
setle D
| setnle
setnl
setnge
setng
| D <- ~(SF ^OF) & ZF
D <- ~(SF ^OF)
D <- SF ^ OF
D <- (SF ^ OF) | ZF
| 大于(有符号>)
小于等于(有符号>=)
小于(有符号<)
小于等于(有符号<=)
|
seta D
setae D
setb D
setbe D | setnbe
setnb
setnae
setna | D <- ~CF & ~ZF
D <- ~CF
D <- CF
D <- CF | ZF
| 超过(无符号>)
超过或等于(无符号>=)
低于(无符号<)
低于或等于(无符号<=) |
(2).根据条件码跳转
根据条件码跳转,跳转目的地用一个label指明(类似于c中goto标签):
指令 | 同义名 | 跳转条件 | 描述 |
jmp Label
jmp *Operand
|
| 1
1 | 直接跳转,跳转指令中给出位置
间接跳转,跳转位置由寄存器给出 |
je Label
jne Label
| jz
jnz | ZF
~ZF
| 等于/零
不等/非零
|
js Label
jns Label
|
| SF
~SF
| 负数
非负数
|
jg Label
jge Label
jl Label
jle Label
| jnle
jnl
jnge
jng
| ~(SF^OF) & ~ZF
~(SF ^ OF)
SF ^ OF
(SF ^ OF) | ZF
| 大于(有符号>)
大于等于(有符号>=)
小于(有符号<)
小于等于(有符号<=)
|
ja Label
jae Label
jb Label
jbe Label
| jnbe
jnb
jnae
jna
| ~CF & ~ZF
~CF
CF
CF | ZF
| 超过(无符号>)
超过或等于(无符号>=)
低于(无符号<)
低于或等于(无符号<=) |
4.转移指令(过程控制)
实现函数过程调用和返回相关指令。
指令 | 描述 |
call label | 过程调用 |
call *operant | 过程调用 |
leave | 为返回准备栈 |
ret | 从过程调用中返回 |
至此,CPU硬件和汇编相关的概述已经完全介绍完全了,下一部分将是底层相关的多级存储的一些知识总结。
本系列文章:
计算机底层架构(偏硬件)综述
计算机处理器(CPU)基础
汇编语言基础--机器级数据存储
汇编语言基础--汇编操作指令概述
计算机多级存储模型
外设IO原理
这篇关于汇编语言基础--汇编操作指令概述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!