汇编指令二进制代码手册.docx
《汇编指令二进制代码手册.docx》由会员分享,可在线阅读,更多相关《汇编指令二进制代码手册.docx(734页珍藏版)》请在冰豆网上搜索。
汇编指令二进制代码手册
汇编指令与二进制代码对应手册
汇编指令与二进制代码具有一一对应关系,也就是说,一条汇编指令必将唯一对应一条二进制代码指令,而一条二进制代码指令也唯一对应一条汇编指令,这就为写一个汇编语言与二进制指令相互对应的参考表成为可能。
手册的使用范围
本手册的读者需要据有一定的计算机专业知识,了解CPU的工作原理及内部的体系结构,熟悉IBM汇编、NASM或其它汇编语言,并且对汇编语言指令的二进制代码有足够的兴趣。
本手册列出了绝大部分的中文汇编指令与二进制指令的对应关系,及相应的英文汇编指令名称。
由于作者水平有限,而且本手册主要是对照NASM汇编语言指令集、《Intel微处理器结构、编程与接口》中文第六版及其Intel公司公布的《IA-32IntelArchitectureSoftwareDeveloper’sManual》2001年版的PDF格式文档指令集而生成的,或许有一些比较新的指令或者其他CPU特有的指令,并未收集在本手册中。
汇编指令解析
一、操作码汇编指令按其功能可分为:
一般指令、浮点指令、多媒体指令和SIMD流式扩展(SSE)指令。
汇编指令因其繁多且对应的二进制代码有多种变化而变得异常复杂,二进制代码的指令都是由操作码与操作数构成,就指令与操作数的关系而言,指令无非是无操作数、单操作数、双操作数和三操作数。
所谓的操作码就是唯一代表着指令的意义的一段二进制码,操作码可以是单字节或者是双字节。
有一种特殊的操作码,它与操作数合起来共用一个字节或者两个字节,这种操作码的操作数都是寄存器,而且寄存器的二进制代码都为这操作码字节的最后三位,在参照表中用“操作数指令”字段表示,如果这个段中的数据为“是”就表示这个操作码是与寄存器操作数共用一个字节或两个字节,否则就不是。
从对照表中,我们可以看出,实事上二进制操作码与汇编指令名称并非一一对应,一条汇编指令的名称如:
转移指令,它可以对应多个操作码,只有当指令名称与指令操作数合在一起,才与操作码和操作数有一一对应的关系。
也就是说同一个指令名称,指令操作数类型不同,对应的二进制操作码也可能不同。
操作码在对照表是用“操作码”字段表示。
在操作码字节中通常又有方向位、符号位、操作数大小修饰位值得注意,它们都用一个二进制位来表示,方向位与符号位通常都在操作码的倒数第二位,而操作数修饰位通常在操作码的最后一位。
举例说明:
如果倒数第二位是方向位,那么如果这一位值为0,那么表示操作数是从左到右,如果是1表示操作数从右到左;如果倒数第二位是表示符号位,那么如果这一位值为0表示操作数是无符号操作数,如果值为1表示操作数为有符号操作数;如果最后一位是修饰操作数位,那么最后一位为0表示操作数是八位操作数,就是字节操作数,最后一位为1表示操作数大小由汇编模式决定,如果是16位汇编就表示是16位操作数,即字操作数,如果是32位汇编就表示是32位操作数,即双字操作数。
汇编模式是16位还是32位,由汇编代码决定,在NASM汇编中默认为32位模式,如果代码显示地给出BIT16就表示汇编成16位模式,如果代码显示地给出BIT32就表示汇编成32位模式。
汇编模式不同,操作数也不相同,具体请看操作数节中介绍。
二、操作数计算机指令之所以复杂的一个主要原因就是操作数有多种变化,最为简单的指令就是无操作数指令。
其中操作数可以是立即数、寄存器和内存地址。
通常情况下,操作数含有立即数的指令与不含立即数的指令,指令操作码不同;操作数都为寄存器的,通用寄存器、段寄存器、控制寄存器、调试寄存器和任务寄存器的指令操作码不同;多媒体指令、浮点指令和SIMD指令都有各自的指令系统。
最为复杂的变化是当操作数为寄存器或内存的时候,之所以把它们放在一起,是因为它们都由一个叫做模数(MOD)的两位二进制数来决定。
计算机指令是如何分辨多变的操作数的呢?
前面提到,如果操作数是立即数,那么就用操作码来区分。
当操作数是寄存器或是内存地址时,主要是用一个字节来区分,这个字节的前两位就是模数(MOD),后三位是寄存器的二进制代码,最后三位的值由开始两位的模数来决定具体的类型,如果模数为11那么最后三位就用来表示寄存器。
内存地址是用寄存器的值来表示的,有的内存地址带有位移量,于是,当模数为00时字节的最后三位就表示寄存器内的数据是内存地址,并且没有位移量,当模数为01时,字节最后三位表示寄存器内的数据是内存地址,并且在这一字节之后有8位数的位移量,当模数为10时字节后面有16位或32位,是16位还是32位由汇编模式来决定。
16位模式常用于实模式,可使用16位寄存器,如AX、BX等,32位常用于保护模式,可使用32位寄存器,如EAX、EBX等。
然而,只用一个字节的最后三位来表示内存地址,不可能用来表示众多的寄存器组合,于是模数为00时(没有位移量),就有在16位汇编模式,当nnn=000(nnn表示是用来表示内存的三位二进制数)时,内存地址为DS:
[BX+SI],在32位汇编模式时nnn=000,内存地址为DS:
[EAX],其它的值请参照后面的对应表。
于是,我们知道了,计算机指令是通过模数、寄存器和寄/内三个域来决定操作数的,其实除此之外,还有一种特殊的情况,就是操作数并没有都用到这三个域,而是把第二个域的值设为一个预设值,也就是说,第二个用来表示寄存器的域设成了固定值,而不是可变的寄存器,那么这就出现了只有一个寄存器或是内存地址操作数的变型,其实它是由前一种类型变化得来的。
有三个操作数的指令又是如何的呢?
实事上搞明白了上一种变化,三个操作数就很容易了,它只不过是在两个寄存器或内存地址操作数之后再加一个立即数,这种情况同样有一种特例,那就是有两个相同寄存器操作数,和一个立即数,那么在写汇编代码的时候就把这种情况认为是一个寄存器和一个立即数,而实际翻译成二进制代码时要翻译成两个相同的寄存器和一个立即数,它同样是属于三个操作数的情况,IMUL指令就属于这一种特例。
在具体的指令中还有一些例外,比如,一个看上去只有一个操作码,不含操作数的指令,而实际上它有隐含的寄存器作为它的操作数如计数寄存器,或者它的寄存器操作数被指令指定了,而不是可变的,如只使用累加寄存器,这也是比较常见的,这些在对照表中有详细的注明。
三、指令前缀有些指令通过添加前缀来改变默认段或超越指令模式。
所谓超越指令模式是指在16位汇编模式时使用了32位的寄存器或者由32位寄存器组成的内存地址,或者在32位汇编模式时使用了16位寄存器或者由16位寄存器组成的内存地址。
当使用超越前缀时,应把前缀字节放在指令的面前,有多个前缀时前缀字节没有顺序地排列。
超越前缀表
前缀字节作用
26HES:
段超越前缀
2EHCS:
段超越前缀
36HSS:
段超越前缀
3EHDS:
段超越前缀
64HFS:
段超越前缀
65HGS:
段超越前缀
2EH分支未获取前缀(原英文是:
Branchnottaken,分支暗示前缀--仅用于条件跳转(Jcc)指令)
3EH分支被获取前缀(原英文是:
Branchtaken,分支暗示前缀--仅用于条件跳转(Jcc)指令)
66H对操作数长度的指令模式超越
67H对内存地址长度的指令模式超越
F0H锁(LOCK)指令前缀
F2H不相等重复/不为零重复前缀(REPNE/REPNZ)指令前缀(只适用于字符串操作指令)
F3H重复(REP)指令前缀(只适用于字符串操作指令)
F3H相等重复/为零重复前缀(REP/REP)指令前缀(只适用于字符串操作指令)
四、总结通过以上的分析,我们可以总结出计算机指令的结构,由于286以前(含286)的处理器只能识别16位地址指令,且不能识别超越前缀字节,因此,这种16位地址指令的格式又与32位地址,即386以后(含386)的处理器的指令格式有所不同,如下表:
16位计算机指令格式(适用于286以前的处理器)
操作码
操作数
0x…
带模数的寄存器和寄/内操作数
内存位移量
立即数
1-2字节
0-1字节
0-2字节
0-2字节
32位计算机指令格式(适用于386以后的处理器)
指令超越前缀
操作码
操作数
0x66/0x67…
0x…
带模数的寄存器和寄/内操作数
比例变址*
内存位移量
立即数
由前缀个数而定
1-2字节
0-1字节
0-1字节
0-4字节
0-4字节
*值得注意的是,操作数域中的比例变址只适用于32位寻址方式,且此时jjj/nnn=100比例变址字节的前两位表示比例因子,后三位表示变址寄存器,最后三位表示基地寄存器,最终得到的地址值是:
比例因子*变址+基址,当比例因子为00时乘以1,当比例因子为01是乘以2,当比例因子为10时乘以4,当比例因子为11时乘以8。
其中“带模数的寄存器和寄/内操作数”这一操作数域仅占一个字节,如下表示:
mmjjjjjj/nnnmm是两位模数jjj是三位表示的寄存器nnn是三位用寄存器的值来表示的内地地址
当mm=11时jjj/nnn的值就表示为寄存器,即:
11jjjjjj
当mm=00时jjj/nnn的值就表示为内存地址,即:
00jjjnnn且此时“内存位移量”域不取值,没有位移量
当mm=01时jjj/nnn的值就表示为内存地址,即:
01jjjnnn且此时“内存位移量”域取8位的位移量
当mm=10时jjj/nnn的值就表示为内存地址,即:
10jjjnnn且此时“内存位移量”域取16位或32位的位移量,如果是16位汇编模式则取16位的位移量,如果是32位汇编模式则取32位的位移量。
是否有最后面的立即数操作数则由操作码来决定。
如果汇编代码指定为16位汇编模式,但指令的操作数中使用了32位的寄存器,则就需要在指令前加0x66的超越前缀,如果是使用了32位寄存器的值来表示内存地址,则需要在指令前加0x67的超越前缀,同理,汇编代码指定为32位汇编模式时,在指令的操作数中使用了16位的寄存器,也需要在指令前加0x66的超越前缀,如果是使用了16位寄存器的值来表示内存地址,则需要在指令前加0x67的超越前缀。
其每条指令的这两种超越前缀已经在指令对照表中完整给出。
寄存器中文-英文命名对照表
类型
中文名称
英文名称
二进制码
寄存器说明
多功能寄存器
累加低八
AL
000
累加寄存器低八位
累加高八
AH
100
累加寄存器低八位
累加16
AX
000
16位累加寄存器
累加32
EAX
000
32位累加寄存器
基址低八
BL
011
基址寄存器低八位
基址高八
BH
111
基址寄存器低八位
基址16
BX
011
16位基址寄存器
基址32
EBX
011
32位基址寄存器
计数低八
CL
001
计数寄存器低八位
计数高八
CH
101
计数寄存器低八位
计数16
CX
001
16位计数寄存器
计数32
ECX
001
32位计数寄存器
数据低八
DL
010
数据寄存器低八位
数据高八
DH
110
数据寄存器低八位
数据16
DX
010
16位数据寄存器
数据32
EDX
010
32位数据寄存器
类型
中文名称
英文名称
二进制码
寄存器说明
指针寄存器
堆栈指针16
SP
100
16位堆栈指针寄存器
堆栈指针32
ESP
100
32位堆栈指针寄存器
基址指针16
BP
101
16位基址指针寄存器
基址指针32
EBP
101
32位基址指针寄存器
变址寄存器
目标变址16
DI
111
16位目标变址寄存器
目标变址32
EDI
111
32位目标变址寄存器
源变址16
SI
110
16位源变址寄存器
源变址32
ESI
110
32位源变址寄存器
专用寄存器
指令指针16
IP
*
16位指令指针寄存器
指令指针32
EIP
*
32位指令指针寄存器
标志16
FLAGS
*
16位标志寄存器
标志32
EFLAGS
*
32位标志寄存器
段寄存器
代码段
CS
001
代码段寄存器
数据段
DS
011
数据段寄存器
附加段
ES
000
附加段寄存器
堆栈段
SS
010
堆栈段寄存器
标志段
FS
100
标志段寄存器
全局段
GS
101
全局段寄存器
控制寄存器
控制零
CR0
000
控制寄存器零
控制一
CR1*
001
控制寄存器一
控制二
CR2
010
控制寄存器二
控制三
CR3
011
控制寄存器三
控制四
CR4
100
控制寄存器四
控制五
CR5*
101
控制寄存器五
控制六
CR6*
110
控制寄存器六
控制七
CR7*
111
控制寄存器七
调试寄存器
调试零
DR0
000
调试寄存器零
调试一
DR1
001
调试寄存器一
调试二
DR2
010
调试寄存器二
调试三
DR3
011
调试寄存器三
调试四
DR4*
100
调试寄存器四
调试五
DR5*
101
调试寄存器五
调试六
DR6
110
调试寄存器六
调试七
DR7
111
调试寄存器七
任务寄存器
任务零
TR0
000
任务寄存器零
任务一
TR1
001
任务寄存器一
任务二
TR2
010
任务寄存器二
任务三
TR3
011
任务寄存器三
任务四
TR4
100
任务寄存器四
任务五
TR5
101
任务寄存器五
任务六
TR6
110
任务寄存器六
任务七
TR7
111
任务寄存器七
浮点寄存器
浮点零
ST0
000
浮点寄存器零
浮点一
ST1
001
浮点寄存器一
浮点二
ST2
010
浮点寄存器二
浮点三
ST3
011
浮点寄存器三
浮点四
ST4
100
浮点寄存器四
浮点五
ST5
101
浮点寄存器五
浮点六
ST6
110
浮点寄存器六
浮点七
ST7
111
浮点寄存器七
多媒体寄存器
媒体零
MM0
000
媒体寄存器零
媒体一
MM1
001
媒体寄存器一
媒体二
MM2
010
媒体寄存器二
媒体三
MM3
011
媒体寄存器三
媒体四
MM4
100
媒体寄存器四
媒体五
MM5
101
媒体寄存器五
媒体六
MM6
110
媒体寄存器六
媒体七
MM7
111
媒体寄存器七
单指令流、多数据流寄存器
单流零
XMM0
000
单指令流、多数据流寄存器零
单流一
XMM1
001
单指令流、多数据流寄存器一
单流二
XMM2
010
单指令流、多数据流寄存器二
单流三
XMM3
011
单指令流、多数据流寄存器三
单流四
XMM4
100
单指令流、多数据流寄存器四
单流五
XMM5
101
单指令流、多数据流寄存器五
单流六
XMM6
110
单指令流、多数据流寄存器六
单流七
XMM7
111
单指令流、多数据流寄存器七
注:
英文名称有星号“*”的表示作为保留域,实际并没有使用,二进制码有星号“*”表示无需二进制数表示
寻址方式
16位寻址方式时模数mm与内存寻址nnn可能的组合
mmnnn寻址方式中文表示寻址方式英文表示
00000数据段:
[基址16+源变址16]DS:
[BX+SI]
00001数据段:
[基址16+目标变址16]DS:
[BX+DI]
00010堆栈段:
[基址指针16+源变址16]SS:
[BP+SI]
00011堆栈段:
[基址指针16+目标变址16]SS:
[BP+DI]
00100数据段:
[源变址16]DS:
[SI]
00101数据段:
[目标变址16]DS:
[DI]
00110堆栈段:
[基址指针16]SS:
[BP]
00111数据段:
[基址16]DS:
[BX]
01000数据段:
[基址16+源变址16+8位符号位移]DS:
[BX+SI+sign_disp8]
01001数据段:
[基址16+目标变址16+8位符号位移]DS:
[BX+DI+sign_disp8]
01010堆栈段:
[基址指针16+源变址16+8位符号位移]SS:
[BP+SI+sign_disp8]
01011堆栈段:
[基址指针16+目标变址16+8位符号位移]SS:
[BP+DI+sign_disp8]
01100数据段:
[源变址16+8位符号位移]DS:
[SI+sign_disp8]
01101数据段:
[目标变址16+8位符号位移]DS:
[DI+sign_disp8]
01110堆栈段:
[基址指针16+8位符号位移]SS:
[BP+sign_disp8]
01111数据段:
[基址16+8位符号位移]DS:
[BX+sign_disp8]
10000数据段:
[基址16+源变址16+16位符号位移]DS:
[BX+SI+disp16]
10001数据段:
[基址16+目标变址16+16位符号位移]DS:
[BX+DI+disp16]
10010堆栈段:
[基址指针16+源变址16+16位符号位移]SS:
[BP+SI+disp16]
10011堆栈段:
[基址指针16+目标变址16+16位符号位移]SS:
[BP+DI+disp16]
10100数据段:
[源变址16+16位符号位移]DS:
[SI+disp16]
10101数据段:
[目标变址16+16位符号位移]DS:
[DI+disp16]
10110堆栈段:
[基址指针16+16位符号位移]SS:
[BP+disp16]
10111数据段:
[基址16+16位符号位移]DS:
[BX+disp16]
注意:
当处理器执行时,将所有8位符号位移量符号扩展成16位的位移量,如果8位的位移量是00H-7FH(正的),则在位移地址之前扩展成0000H-007FH,如果8位的位移量是80H-FFH(负的),则在位移地址之前扩展成FF80H-FFFFH,因此,这个工作也可由汇编器来完成,在编译时将模数设为10,地址扩展成16的位移量,所以有些汇编程序不使用8位的位移量。
32位寻址方式时模数mm与内存寻址nnn及比例因子字节基址域jjj可能的组合
mmnnnjjj寻址方式中文表示寻址方式英文表示
00000-数据段:
[累加32]DS:
[EAX]
00001-数据段:
[计数32]DS:
[ECX]
00010-数据段:
[数据32]DS:
[EDX]
00011-数据段:
[基址32]DS:
[EBX]
00100000数据段:
[累加32+比例变址]DS:
[EAX+比例变址]
00100001数据段:
[计数32+比例变址]DS:
[ECX+比例变址]
00100010数据段:
[数据32+比例变址]DS:
[EDX+比例变址]
00100011数据段:
[基址32+比例变址]DS:
[EBX+比例变址]
00100100数据段:
[堆栈指针32+比例变址]DS:
[ESP+比例变址]
00100101数据段:
[32位位移量+比例变址]DS:
[32位位移量+比例变址]
00100110数据段:
[源变址32+比例变址]DS:
[源变址32+比例变址]
00100111数据段:
[目标变址32+比例变址]DS:
[目标变址32+比例变址]
00101-数据段:
[32位位移量]DS:
[32位位移量]
00110-数据段:
[源变址32]DS:
[ESI]
00111-数据段:
[目标变址32]DS:
[EDI]
01000-数据段:
[累加32+8位位移量]DS:
[EAX+8位位移量]
01001-数据段:
[计数32+8位位移量]DS:
[ECX+8位位移量]
01010-数据段:
[数据32+8位位移量]DS:
[EDX+8位位移量]
01011-数据段:
[基址32+8位位移量]DS:
[EBX+8位位移量]
01100000数据段:
[累加32+比例变址+8位位移量]DS:
[EAX+比例变址+8位位移量]
01100001数据段:
[计数32+比例变址+8位位移量]DS:
[ECX+比例变址+8位位移量]
01100010数据段:
[数据32+比例变址+8位位移量]DS:
[EDX+比例变址+8位位移量]
01100011数据段:
[基址32+比例变址+8位位移量]DS:
[EBX+比例变址+8位位移量]
01100100堆栈段:
[堆栈指针32+比例变址+8位位移量]SS:
[ESP+比例变址+8位位移量]
01100101堆栈段:
[基址指针32+比例变址+8位位移量]SS:
[EBP+比例变址+8位位移量]
01100110数据段:
[源变址32+比例变址+8位位移量]DS:
[ESI+比例变址+8位位移量]
01100111数据段:
[目标变址32+比例变址+8位位移量]DS:
[EDI+比例变址+8位位移量]
01101-堆栈段:
[基址指针32+8位位移量]SS:
[EBP+8位位移量]
01110-数据段:
[源变址32+8位位移量]DS:
[ESI+8位位移量]
01111-数据段:
[目标变址32+8位位移量]DS:
[EDI+8位位移量]
10000-数据段:
[累加32+32位位移量]DS:
[EAX+32位位移量]
10001-数据段:
[计数32+32位位移量]DS:
[ECX+32位位移量]
10010-数据段:
[数据32+32位位移量]DS:
[EDX+32位位移量]
10011-数据段:
[基址32+32位位移量]DS:
[EBX+32位位移量]
10100000数据段:
[累加32+比例变址+32位位移量]DS:
[EAX+比例变址+32位位移量]
10100001数据段:
[计数32+比例变址+32位位移量]DS:
[ECX+比例变址+32位位移量]
10100010数据段:
[数据32+比例变址+32位位移量]DS:
[EDX+比例变址+32位位移量]
10100011数据段:
[基址32+比例变址+32位位移量]DS:
[EBX+比例变址+32位位移量]
10100100堆栈段:
[堆栈指针32+比例变址+32位位移量]SS:
[ESP+比例变址+32位位移量]
10100101堆栈段:
[基址指针32+比例变址+32位位移量]SS:
[EBP+比例变址+32位位移量]
10100110数据段:
[源变址32+比例变址+32位位移量]DS:
[ESI+比例变址+32位位移量]
10100111数据段:
[目标变址32+比例变址+32位位移量]DS:
[EDI+比例变址+32位位移量]
10101-堆栈段:
[基址指针32+32位位移量]SS:
[EBP+32位位移量]
10110-数据段:
[源变址32+32位位移量]D