保护模式、实地址模式及V8086模式下的指令格式(上)

来源:互联网 发布:windows 安卓共享 编辑:程序博客网 时间:2024/05/07 05:44

保护模式、实地址模式及V8086模式下的指令格式(上)


本文译自《intel指令手册2.1节》,该手册地址为:
http://www.intel.com/products/processor/manuals/index.htm

Intel64和IA32架构的指令编码格式是图2-1格式的子集。指令有这几个部分组成:可选的指令前缀(顺序不限)、主操作码字节(最多3个字节)以及寻址方式说明(addressing-form specifier)字节(如果需要的话)。寻址方式说明由ModR/M字节、SIB字节、位移量(如果需要的话)和立即数(如果需要的话)组成。


图2-1Intel64和IA-32架构指令格式

 

2.1.1 指令前缀
指令前缀分成四块,每块都有一组前缀代码。对于每个指令来说,四块中每块只能使用一个前缀。这四块的前缀的顺序是不限定的。

•第一块
—锁前缀和重复前缀:
•LOCK锁前缀代码为F0H
•REPNE/REPNZ前缀代码为F2H。该前缀仅用于字符串和输入/输出指令(F2H在某些指令中还被用作强制前缀(mandatory prefix)).
• REP或者REPE/REPZ前缀代码为F3H。该前缀仅用于字符串和输入/输出指令(F3H在某些指令中还被用作强制前缀).

•第二块
—段超越前缀
• 2EH——CS段超越(在分支指令中使用未定义)
• 36H——SS段超越(在分支指令中使用未定义)
• 3EH——DS段超越(在分支指令中使用未定义)
• 26H——ES段超越(在分支指令中使用未定义)
• 64H——FS段超越(在分支指令中使用未定义)
• 65H——GS段超越(在分支指令中使用未定义)
—分支预测(branch hints)前缀
• 2EH——分支被使用(只用于条件转移JCC指令)
• 3EH——分支不被使用(只用于条件转移JCC指令)

• 第三块
•调整操作数大小(operand-size override)前缀代码为66H(在一些指令中66H被用作强制前缀)

• 第四块
•67H——调整地址大小(address-size override)前缀

锁前缀(F0H)在多处理器情况下会迫使一个操作必须互斥地使用共享内存。(详见《“Instruction Set Reference, A-M,”》 第三章“LOCK—Assert LOCK# Signal Prefix”)

重复前缀(F2H,F3H)会使指令对字符串中的每一个元素都重复执行。该前缀只在字符串和I/O指令(MOVS,CMPS, SCAS,LODS,STOS,INS,OUTS)中使用。在其他未定义的操作码前使用重复前缀没有定义,这种使用会导致不可预见的后果。
一些指令会将F2H/F3H作为强制前缀来表示不同的功能(express distinct functionality)。强制前缀通常应置于其他可选前缀后面(例外情况在2.2.1“REX Prefixes”中讨论)。

分支预测前缀(2EH,3EH)允许程序预测一个分支最有可能的路径。此前缀只在条件转移指令(JCC)中使用。在其他未定义的操作码前使用分支预测前缀没有定义,这种使用会导致不可预见的后果。

调整操作数大小前缀(66H)允许程序在16位和32位操作数之间切换操作数。这两种大小都可以作为缺省值,使用本前缀可以切换为非缺省的那个大小值。

一些SSE2/SSE3/SSSE3/SSE4指令和主操作码为3字节的指令可能会将66H作为强制前缀来表示不同的功能。强制前缀通常应置于其他可选前缀后面(例外情况在2.2.1“REX Prefixes”中讨论)。
66H前缀的其他使用保留,如果使用可能会导致不可预见的后果。

调整地址大小前缀(67H)允许程序在16位和32位地址之间切换。这两种大小都可以作为缺省值,使用本前缀可以切换为非缺省的那个大小值。当指令的操作数是内存中不存在时,使用该前缀和/或者未定义的操作码是未定义的,这种使用会导致不可预见的后果。
.
2.1.2 操作码
主操作码可以是1个,2个或3个字节长。有时会有另外的3位操作码存在于ModR/M字节中。主操作码中还可以为定义更小的段(fields),比如操作方向、位移量(displacements)大小、寄存器编码、条件码(condition codes)或者符号扩展(sign extension)。操作码中的段随操作的类型不同而有很大的不同。

通用指令和SIMD指令的2个字节的操作码格式组成如下:
•一个逃逸码(escape opcode)0FH作为主操作码和一个第二操作码字节。或者
•一个强制前缀(66H、F2H或F3H),一个逃逸码字节和一个第二操作码字节。
举例说明,CVTDQ2PD的操作码序列为F3 0F E6。第一个字节就是强制前缀(不是重复前缀)。

通用指令和SIMD指令的3个字节的操作码格式组成如下:
•一个逃逸码0FH作为主操作码,加上两个额外的操作码字节。或者
•一个强制前缀(66H、F2H或F3H),一个逃逸码字节,加上两个额外的操作码字节。
举例说明,XMM寄存器的PHADDW指令的操作码序列为66 0F 38 01。第一个字节就是强制前缀。

所有有效的操作码列于附录A和附录B.

2.1.3 ModR/M和SIB字节
很多引用内存操作数的指令需要一个说明寻址方式的字节(称为ModR/M)紧跟在主操作码后面。ModR/M字节包含下面三个信息段(译注:见图2-1):
•Mod段和r/m段形成32种可能值:8种寄存器和24种寻址方式。
•Reg/Opcode段或者指定一个寄存器或者是主操作码的3位附加信息。Reg/opcode段的具体作用由主操作码决定。
•r/m段可以指定一个寄存器作为操作数,或者和mod段组合起来指定一种编码方式。有时候,这种mod段和r/m段的组合可以被用来表示一些指令的操作码信息。

一些ModR/M字节还需要第二个寻址字节(SIB)。32位的基址变址(base-plus-index)和比例变址(scale-plus-index)寻址方式需要一个SIB字节。SIB字节包含下面段(译注:见图2-1):
•比例段指出比例倍数(scale factor)
•变址段指出变址寄存器的寄存器数字
•基址段指出基址寄存器的寄存器数字
参看2.1.5节ModR/M和SIB字节的编码

2.1.4位移量和立即数字节
一些寻址方式在ModR/M(或者SIB,如果有的话)后面会有一个位移量。如果有位移量的话,它可以是1、2或4字节。如果一个指令指定一个立即数,那么这个立即数会跟在位移量字节后面,立即数可以是1、2和4字节。

2.1.5 ModR/M和SIB字节组成的寻址方式
由ModR/M和SIB字节组成的值和其对应的寻址方式列于表2-1到表2-3:由ModR/M字节指定的16位寻址方式列于表2-1;32位寻址方式列于表2-2;表2-3列出了由SIB字节指定的32位寻址方式。假如ModR/M字节中reg/opcode段表示一个扩展操作码,有效编码见附录B.

在表2-1和表2-2中,有效地址(Effective Address)列中列出了由Mod和R/M组成的可以赋给指令的第一个操作数的32种有效地址。前面24种指出了一个内存的位置;后面的8种(Mod=11B)是指出了通用寄存器、MMX寄存器和XMM寄存器。

表2-1和表2-2中的Mod和R/M列给出了要获得第一列这种有效地址方式的二进制编码。比如,看Mod=11B,R/M=000B那一行,该行标明的通用寄存器为EAX,AX和AL;MMX寄存器为MM0;XMM寄存器为XMM0.具体到底使用哪个寄存器是由操作码字节和操作数大小属性决定。

我们再来看表2-1或2-2任一个表的第7行(标有“REG=”的那行)。该行指出如何使用3位的Reg/Opcode段来获得第二个操作数的位置。第二个操作数必须是通用寄存器、MMX寄存器或者XMM寄存器。第1到5行列出了表中值所对应的寄存器。和上面一样,使用哪种寄存器是由操作码字节和操作数大小属性决定的。

如果指令不需要第二个操作数,Reg/Opcode段可以被用作操作码的扩展。由表的第6行(标有“/DIGIT(OPCODE)”的那行)标出。注意该行值是十进制形式的。

表2-1和表2-2的主体部分(在标有“Value of ModR/M Byte (in Hexadecimal)”的下面)包含一个由32*8数组所表示的256个ModR/M值(16进制)。第3/4/5位由字节所在列指出,第0/1/2位和第6/7位由行指出。下图演示如何计算出表中值的。

 

图2-2 解释如何得到ModR/M(C8H)字节

 

 

 


表2-3显示的是256中SIB字节的可能值(16进制)。用作基址的通用寄存器列在表的上部,并同时显示了在SIB字节中的对应值。表的主体部分的行是作为变址的寄存器和比例倍数(由SIB字节的第6/7位表示).

 

 

参考文献
1.    http://linux.chinaunix.net/bbs/thread-1050480-1-1.html。
2.    http://blog.ftofficer.com/2010/04/n-forms-of-call-instructions/
3.    http://baike.baidu.com/view/889427.htm?fr=ala0_1