汇编指令不是机器指令,汇编指令是一种文本。需要经过汇编器编译成机器指令才可以在处理器上执行。汇编语言指令与机器指令总体上是1:N。汇编语言允许程序员直接创建指令码程序,而无需担心处理器上众多的指令码的组合,汇编语言使用助记符表示指令,助记符使程序员可以使用英语样式的词表示各个指令,这样汇编器很容易地把汇编语言翻译成原始的机器指令。
x86 nasm汇编指令格式为。
[label]: mnemonic [operands] [;commemt]
指令包含的操作数可以是0,1,2,3个。操作数可以有三种类型。
- 立即操作数(immediate operand):使用数字文本表示
- 寄存器操作数(register):使用cpu内已命名的寄存器
- 内存操作数(memory): 引用内存的位置。
使用汇编语言可以不了解指令码的每个字节的详细信息,使用更简单的助记符来表示指令。不同的汇编器使用不同的助记符表示指令码。应用比较广泛的有MSVC的MASM, AT&T,intel,还有本章节讨论的NASM。
- MASM: 只能在windows系统下使用。
- AT&T: gcc编译器使用了AT&T作为默认的汇编器,也可以通过配置替换。AT&T是一个跨平台的汇编器,可以在多个系统下使用。
- INTEL: intel出的汇编格式。MASM和NAMS的汇编格式和intel类似。
- NASM: 跨平台,使用简单。
数据传送指令
mov指令
mov destination,source
将源操作数复制到目的操作数
- 两个操作数必须是同样的大小
- 两个操作数不能同时为内存操作数
- 指令指针寄存器(IP,EIP,RIP)不能作为目标操作数
mov指令不能直接将较小的操作数复制到较大的操作数。当可以使用寄存器的地位进行操作实现。
mov eax,0
mov ax,bx
mov reg,reg
mov mem,reg
mov reg,men
mov mem,imm
mov reg,imm
movzx指令
** movzx destination,source**
将操作数复制到目的操作数,并把目的操作数0扩展到16位或32位或64位。这条指令只能用于无符号整数。
movzx reg32, reg/mem8
movzx reg32, reg/mem16
movzx reg16, reg/mem8
movsx指令
** movzx destination,source**
将操作数复制到目的操作数,并把目的操作数扩展到16位或32位或64位。这条指令只能用于有符号整数。
movsx reg32, reg/mem8
movsx reg32, reg/mem16
movsx reg16, reg/mem8
xchg指令
xchg destination,source
指令交换两个操作数内容。xcha的要求和mov指令操作数要求一样
xchg reg,reg
xchg reg,mem
xchg mem,reg
xadd指令
先交换仔累加
cmpxchg指令
bawap指令
lahf指令
sahf指令
算术运算指令
inc/dec 指令
inc/dec destination
int/dec指令分别表示寄存器或者内存操作数+1或者-1
inc reg/mem
dec reg/mem
add指令
** add destination ,source **
将长度相同的源操作数和目的操作数进行相加
add reg, reg
add mem,reg
add regm men
add mem,imm
add reg,imm
sub指令
sub destionation, source
从目的操作数减去源操作数。指令对操作数的要求和ADD,MOV指令相同
sub reg, reg
sub mem,reg
sub regm men
sub mem,imm
sub reg,imm
neg(非)
neg destionation
neg指令通过把操作数转换为二进制补码,将操作数的符号取反。(将目标操作数按位取反再加1,就可以得到这个数的二进制补码)
neg reg
neg mem
mul指令
mul source
mul用于无符号整数的乘法指令,操作数不能使用立即数,默认使用al/ax/eax/rax寄存器作为目的操作数。有四种类型。
- 指令执行8位操作数与AL寄存器的乘法,并把乘积过存放AX寄存器中。
- 指令执行16位操作数与AX寄存器的乘法,并把乘积存放在DX:AX寄存器中。
- 指令执行32位操作数与EAX寄存器的乘积,并不结果存放在EDX:EAX寄存器中
- 指令执行62位操作数与RAX寄存器的乘积,并不结果存放在RDX:RAX寄存器中 | 被乘数 | 乘数 | 乘积 | | :—-: | :—-: | :—-: | | AL | reg/mem8 | AX | | AX | reg/mem16 | DX:AX | | EAX | reg/mem32 | EDX:EAX | | RAX | reg.mem32 | RDX:RAX |
mul reg/mem8
mul reg/mem16
mul reg/mem32
mul reg/mem64
imul指令
imul ``destination
imul用于有符号的整数相乘,与mul指令不同,imul会保留乘积的符号。x86指令集支持三种格式的imul的指令。单操作数,双操作数,三操作数。
- 单操作数
单操作数与mul类似 - 双操作数
- 3操作数
div指令
div source
div指令用于无符号整数除法,操作数不能使用立即数,默认使用dx/edx/rdx和al/ax/eax/rax寄存器作为目的操作数。有四种类型。
被除数 | 除数 | 商 | 余数 |
---|---|---|---|
AX | reg/mem8 | AL | AH |
DX:AX | reg/mem16 | AX | DX |
EDX/EAX | reg/mem32 | EAX | EDX |
RDX/RAX | reg/mem64 | RAX | RDX |
div reg/mem8
div reg/mem16
div reg/mem32
div reg/mem64
idiv指令
idiv source
idive指令用于执行有符号整数的除法,其操作数与div指令一样。
idiv reg/mem8
idiv reg/mem16
idiv reg/mem32
idiv reg/mem64
跳转指令
无条件跳转指令
jmp指令
jmp destination
jmp指令无条件跳转到目标地址,该地址用代码标号来标识,并被汇编器转换为偏移值。
top:.
.
jmp top
call/ret指令
call指令调用一个子程序,指挥着处理器从一个新内存地址开始执行,并使用指令ret
将处理器转回子程序被调用的位置上继续执行下面的指令。在x86下。cpu指令的执行由cs :eip 两个指令控制的。cs是代码程序代码区的起点地址,eip为指向执行指令的偏移值。执行call
指令后,cpu会自动执行push eip
指令。当执行完成子程序后通过执行ret
指令。cpu会自动执行pop eip
,并跳转到eip
指向的地址的执行指令。
#过程/子程序
fun proc
.
.
ret
fun endp
;主函数
main proc
call fun
main endp
条件跳转指令
x86指令布集包括大量的条件跳转指令。他们能比较有符号。无符号整数,并根据单个cpu标记的值或者某个寄存器值来执行操作。条件比较指令只要分为4种类型
- 居于特定标志位的值跳转
- 居于两数是否相等。(循环指令)
- 居于无符号操作数的比较跳转
- 居于有符号操作数的比较跳转
loop指令
loop destination
loop指令,正式称为按照ecx计数器循环,将程序重复特定次数。ecx自动成为计数器,每次循环计数器减1,。loop指令执行分为两步,第一步ecx -1,第二步ecx与0比较。如果ecx不等于0,则跳转到目标给出的标号。mov ax,0 mov ecx, 5 L1: inc ax loop L1 mov bx,ax ; bx = 5
loope/loopz指令
loopz destination
loope标识ecx寄存器为0跳转。loopz指令的工作方式和loop指令相同,只要一个附加条件,ZF位为1。test al,0; 设置ZF位为1. mov ax,0 mov ecx, 5 L1: inc ax loope L1 mov bx,ax ; bx = 5
loopne/loopnz指令
loopne destination
loopne指令与loope相对应,当ecx寄存器中的无符号数值大于0,却标记位等于0的时候。执行跳转。or al,0; 设置ZF位为0. mov ax,0 mov ecx, 5 L1: inc ax loope L1 mov bx,ax ; bx = 5
标记位条件跳转集合
这是标志位条件跳转集合。当标记条件为真时,条件指令跳转到目标标号。否则当标记位条件为假的时候,立即执行条件跳转后面的指令。
指令名 | 说明 | 标记位 |
---|---|---|
JZ(jmp zero) | 为0跳转 | ZF =1 |
JNZ(jmp no zero) | 非0跳转 | ZF=0 |
JC(jmp come) | 进位跳转 | CF=1 |
JNC(jmp no come) | 无进位跳转 | CF=0 |
JO(jmp overflow) | 溢出跳转 | OF=1 |
JNO(jmp no overflow) | 无溢出跳转 | OF=0 |
JS(jmp signed ) | 有符号跳转 | SF=1 |
JNS(jmp no signed) | 无符号跳转 | SF=0 |
JP(jmp parity check) | 偶校验跳转 | PE=1 |
JNP(jmp no parity check) | 奇校验跳转 | PE=0 |
其他条件跳转指令集合
针对了特定的指令或者寄存器进行的跳转指令。cmp leftOp,rightOP
指令相等性条件跳转(有符号和无符号)
指令 | 说明 |
---|---|
JE | 相等跳转(leftOp == rightOp ) |
JNE | 不等跳转(leftOp != rightOp) |
cmp leftOp,rightOP
指令无符号比较跳转
指令 | 说明 |
---|---|
JA | leftOp > rightOp |
JNBE | leftOp > rightOp |
JAE | leftOp >= rightOp |
JNB | leftOp >= rightOp |
JB | leftOp < rightOp |
JNAE | leftOp < rightOp |
JBE | leftOp <= rightOp |
JNA | leftOp <= rightOp |
cmp leftOp,rightOP
指令有符号比较跳转
指令 | 说明 |
---|---|
JG | leftOp > rightOp |
JNLE | leftOp > rightOp |
JGE | leftOp >= rightOp |
JNL | leftOp >= rightOp |
JL | leftOp < rightOp |
JNGE | leftOp < rightOp |
JLE | leftOp <= rightOp |
JNG | leftOp <= rightOp |
CX,ECX,RCX寄存器
指令 | 说明 |
---|---|
JCXZ | CX==0 |
JECXZ | ECX==0 |
JERCXZ | RCX == 0(64位寄存器) |
堆栈操作指令
push指令
push source
push
指令首先减少esp
的值。再将原操作数复制到堆栈中,操作数是16位,则esp -2,操作数是32位,esp-4,操作数是64位,esp-8
push reg/mem16
push reg/mem32
push imm32
pop指令
pop desination
pop指令首先把esp指针指向的堆栈内存复制到一个16位或32位的目的操作数中,再增加esp的值。如果操作数是16位esp+2,如果操作数是32位esp+4
pop reg/mem16
pop reg/mem32
pusha指令
把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
popa指令
把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
pushad指令
把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
popad指令
把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
pushf指令
popf指令
pushd指令
popd指令
比较指令
在高级语言中,通过使用比较指令实现了高级语言的if判断语句,while语句等。
and指令
and destination,source
and指令在两个操作数的对应位之间进行按位与操作。并把结果存放在目标操作数中。操作数可以是8,16,32,64位。但两个操作数必须是同样的大小。两个操作数的每一个对应位都是1,则结果是1,否则等于0.
and reg,reg
and reg,mem
and reg,imm
and mem,reg
and mem,imm
or指令
or destination,source
or指令在两个操作数的对应位进行按位或操作。并把结果存放在目的操作数上,操作数可以是8,16,32,64位。但两个操作数必须是同样的大小。两个操作数的一个对应位是1,则结果是1,否则等0
or reg,reg
or reg,mem
or reg,imm
or mem,reg
or mem,imm
xor指令
xor destination,source
xor指令在两个操作数之间进行异或操作,并把结果存放在目的操作数上。xor指令操作数和and和or指令一样。如果两个位的值相同则结果等于0,否则为1。
xor reg,reg
xor reg,mem
xor reg,imm
xor mem,reg
xor mem,imm
not指令
not destination
not 指令触发操作数所有位把0变,把1变为0。其结果称为反码。
not reg
not mem
test指令
test destination,source
test指令在两个操作数之间进行and操作,并根据运算结果设置符号标志位,零标志位和奇偶标志位。test指令和and指令不同的是,test指令不修改目的操作数。test指令允许的操作数组合和and指令相同。
test reg,reg
test reg,mem
test reg,imm
test mem,reg
test mem,imm
cmp指令
cmp destination, source
cmp指令执行从目的操作数中减去源操作数的隐含减法操作。并且不修改任何的操作数。不同的跳转指令根据标记位执行不同的跳转逻辑。
or reg,reg
or reg,mem
or reg,imm
or mem,reg
or mem,imm
当实际的减法发生的,cmp指令按照计算结果修改溢出,符号,零,进位,辅助进位和奇偶标志位。不同的操作数,标志位有不同的结果过。
两个无符号数
cmp结果 | 零标记位(ZF) | 进位标记位(CF) |
---|---|---|
目的操作数 < 源操作数 | 0 | 1 |
目的操作数 > 源操作数 | 0 | 0 |
目的操作数 = 源操作数 | 1 | 0 |
两个有符号数
cmp结果 | 标记位 |
---|---|
目的操作数 < 源操作数 | SF != OF |
目的操作数 > 源操作数 | SF = OF |
目的操作数 = 源操作数 | ZF =1 |
位移指令
位移标识在操作数中向左或者向右移动。
指令 | 说明 |
---|---|
SHL((shifting left)) | 左移 |
SHR((shifting right)) | 右移 |
SAL(shifting arithmetic left) | 算术左移 |
SAR(shifting arithmetic right) | 算术右移 |
ROL | 循环左移 |
ROR | 循环右移 |
RCL | 带进位的循环左移 |
RCR | 带进位的循环右移 |
SHLD | 双精度左移 |
SHRD | 双精度右移 |
中断指令
int指令
into指令
iret指令
处理器控制指令
hlt指令
wait指令
nop指令
stc指令
clc指令
cmc指令
std指令
cld指令
sti指令
cli指令
清中断允许位.
输出输入指令
in指令
out指令
i/o端口输出