代码反汇编:IDA Pro与Soft ICE之应用(2)

边看边翻译,其中敲字错误或表述有误再所难免。如果您发现错误,而且也有时间,敬请留言告之,以便更正。 请尊重作者及译者工作之艰辛,若转摘,请务必注明出处如下:

------------------------------------------------------------------

《代码反汇编:IDA Pro与Soft ICE之应用》

英文名称:Disassembling Code IDA Pro and Soft ICE

作者:Vlad Pirogov

译者:罗祥勇 <E-mail:solo_lxy@126.com>

出自:CSDN Blog <背你走天涯>专栏

------------------------------------------------------------------

1.2 Intel Pentium 处理器的指令和寄存器

本节我们专注于 Intel Pentium 处理器的指令和寄存器。这些材料将对以后研究可执行文件的二进制代码非常有用。我们这里提供的信息不但对新手很有用,对经验丰富的用户亦然。它可以作为时常放在手边的手册以便参考。

1.2.1 Pentium 微处理器的寄存器

Pentium 微处理器由通用寄存器、标志寄存器、段寄存器、控制寄存器、系统地址寄存器和调试寄存器组成。 EIP 寄存器,又称指令指针,这里保留专门讨论。它包含相对于段起始地址偏移的可执行指令的的地址。此寄存器不能直接访问;然而,很多指令可以间接的改变其内容-例如,过程控制指令。

通用寄存器

通用寄存器包含如下:

  • EAX = (16 + AX = (AH + AL))

  • EBX = (16 + BX = (BH + BL))

  • ECX = (16 + CX = (CH + CL))

  • EDX = (16 + DX = (DH + DL))

  • ESI = (16 + SI)

  • EDI = (16 + DI)

  • EBP = (16 + BP)

  • ESP = (16 + SP)

EAX,EBX,EDX ECX 称之为工作寄存器。注意,这些寄存器都有子寄存器。例如, EAX 寄存器的前 16 位被指派给 AX AX 的低位又指派给 AL ,高位指派给 AH EDI ESI 寄存器被称之索引寄存器。在进行索引操作时有其特殊的作用。 EBP 寄存器被用来寻址堆栈中的参数和局部变量。 ESP 寄存器为堆栈指针,可以通过 PUSH POP CALL 自动修改。 可是,它很少直接使用。 ESI EDI ESP EBP 寄存器也有子寄存器。 例如, EDI 的前 16 位被指派给 DI

标志寄存器

标志寄存器包含 32 位。寄存器各位的用法如下:

0 , 进位标志 CF -这个位在加法或乘法操作时最高为存在借位或进位时被设置为 1

1 1

2 ,奇偶标志 PF -这个位在运算结果的低位字节中包含偶数个 1 时被设置为 1 ,否则为 0

3 0

4 ,辅助进位标志 AF -这个位在某个数的第三位从第四位借位或进位时被设置为 1

5 0

6 ,清零标志 ZF -这个位在操作结果为 0 时被置位,否则被置位 0

7 ,符号标志 SF -这个位与先前一次操作结果数据的最高为相等。

8 ,陷阱标志 TF -这个为在每条指令处理后调用 INT 3 时被设置。该标志用于实模式的调试器。

9 ,中断标志 IF -当清零时不接受外部设备的中断请求。

10 ,方向标志 DF -这个标志用于字符产操作。如果被设置为 1 ,在处理字符串时地址自动递减。

11 ,溢出标志 OF -这个标志在操作数出现溢出的情况时被设置为 1

12 13 ,输入/输出特权级别 (IOPL) -这两个位定义特权级别,这些级别被用于允许代码执行 输入/输出指令或这其他特权指令。

14 ,镶嵌任务标志 NT

15 0

16 ,再继续标志 RF -这个标志在调试断点寄存器时使用。

17 ,虚拟模式标志 VM -在保护模式中,这个标志允许虚拟 8086 模式。

18 ,对齐控制标志 AC -如果这个标志设置为 1 ,当访问一个未对齐的操作符时将抛出 17 号异常。

19 IF 标志的虚拟功能 VIF -该标志使用在保护模式下。

20 ,虚拟中断挂起标志 VIF

21 ,标识指令可用标志。

22 31 ,必须设置为 0

段寄存器

段寄存器包含 CS ,代码段; DS ,数据段; SS ,堆栈段; ES FS;GS 。所有的段寄存器都是 16 位。段寄存器被用于或直接或通过选择子(指向描述符表中的某个结构)的内存地址寻址。

控制寄存器

控制寄存器包含如下:

■ CR0 寄存器

0 ,保护模式允许标志 PE -将处理器切换到保护模式。

1 ,协处理器监视标志 MP -每条 WAIT 指令都会引发 7 号异常。

2 ,协处理器模拟标志 EM -每条指令都会引发 7 号异常。

3 ,任务切换标志 TS -决定选择的协处理器上下文环境是否于当前任务相关。当执行每 条协处理器指令的时候引发 7 号异常。

4 ,扩展类型-指示支持协处理器指令 ET

5 ,数字错误 NE -循序报告协处理器错误的本地机制。

6 15 ,保留未用。

16 ,写保护标志 WP -在超级特权级别下允许些保护。

17 ,保留未用。

18 ,对齐掩码 AM -允许自动对齐检查。

19 28 ,保留未用。

29 ,不允许写透 NW -命中高速缓存或无效周期时禁止写透。

30 ,禁止高速缓存 CD -保护高速缓存不被填充。

31 ,分页标志 PG -当设置为 1 时,允许分页。

■ CR1 保留做将来使用。

■ CR2 当出现页错误时,保存其出错时的线性地址。

■ CR3 20 位存储页目录表的物理地址。其他的位如下:

3 ,分页写透明 PWT -控制写透或回写高速缓存策略。

3 ,分页高速缓存禁止-控制对当前页目录的缓存操作。

■ CR4 寄存器:

0 ,虚拟 8086 模式扩展 VME -当设置为 1 时,允许在虚拟 8086 模式中的中断和异常处理 扩展。

1 ,保护模式虚拟中断 PVI -当设置为 1 时,允许对虚拟中断标志的硬件支持。

2 ,时间印章禁止 TSD- 运行在特权级别 0 时限制 RDTSC 指令的执行。

3 ,调试扩展 DE -在访问输入/输出端口时允许中断。

4 ,分页大小扩展 PSE -当设置为 1 时,允许 4M 的分页。

5 ,物理地址扩展 PAE -当设置为 1 时,允许分页机制至少可以引用 36 位的物理地址。

6 ,允许机器检查 MCE -当设置为 1 时,允许机器检查异常。

7 ,全局分页允许标志 PGE -当设置为 1 时,允许全局的分页机制。

8 ,允许性能监视计数器 PCE -当设置为 1 时,允许在任何运行级别下程序或过程可以执 DPMC 指令。

9 ,对指令 FXSAVE FXRSTOR 指令提供操作系统支持 OSFXSR -当设置为 1 时,允许 FXSAVE FXRSTOR 保存或恢复 XMM MXCSR 指令,其中还包括 X87 浮点单元( FPU )和 MMX 寄存器的内容。

系统地址寄存器

这些寄存器被用于 Intel Pentium 处理器保护模式中。 Windows 操作系统也运行在这样的模式中。

■ GDTR - 六字节寄存器,包含全局描述符表 GDT 的线性地址。

■ IDTR - 六字节寄存器,包含中断描述符表 IDT 的线性地址。

■ LDTR - 六字节寄存器,包含十六位的 GDT 选择子和 8 字节的描述符。

■ TR - 十字节寄存器,包含十六位的 GDT 选择子和 GDT 中八个字节的描述符,用于描述当前任务 状态段 TSS TSS 是一个有特殊格式的段,其包含给定任务的信息和用于任务之间通信的 专用之段。

调试寄存器

■ DR0 DR3 – 这几个寄存器中保存了断点的线性地址。这几个寄存的操作机制描述如下 : 运行程序 的任何地址都将会于存储于其中的地址进行比较,如果有匹配项的话,处理器将会产生调试异常 (INT 1)

■ DR6 (和 DR4 一样)- 这个寄存器反应检查点的状态。这个寄存器的各个位的状态取决于引发调试 异常的调试条件。这个寄存器的重要位描述如下:

0 ,断点条件探测 B0 - 如果本位设置为 0 ,那么意味着当 DR0 中的断点探测到后最后 的异常已经发生。

1 ,和位 1 一样,不过它和 DR1 相关。

2 ,和位 1 一样,不过它和 DR2 相关。

3 ,和位 1 一样,不过它和 DR3 相关。

13 ,调试寄存器访问探测 BD - 保护调试寄存器。

14 ,单步执行 BS - 如果本位置 0 ,意味着标志寄存器的第 8 位被设置为 1 ,而且已经 引发了异常。

15 ,任务切换 BT - 如果本位置 1 ,意味着在任务切换时设置了陷阱标志,而且引发了 异常。

■ DR7 (和 DR5 一样) - 它个各个位控制断点的设置。在这个寄存中,对于每个调试寄存器( DR0 DR3 )的条件都对应相关的位,用于异常的产生。这个寄存器中的前四对( 8 位),每对对应一个 调试寄存器,用于指示相关寄存起能针对本地任务定义断点(这种情况下一个位被设置为 1 )或针 对整个系统定义断点(这种情况下,第二个位必须设置为 1 )。为 16 31 定义访问类型,这意味着 当取指令、读写内存时是否激活中断,并且中定数据大小:

16 17 20 21 24 25 28 29 定义访问类型如下: 00 用于指令, 01 用于写, 11 读和写, 10 目前未用。

18 19 22 23 26 27 30 31 定义从操作数的大小如下: 00 用于字节, 01 用于 双字节, 11 用于 4 字节, 10 目前未用。

1.2.2 主要指令集

主要指令集包含了除协处理器和 MMX 指令以外的所有指令。

以下各表中的命名如下:

■ dest src - 目标操作数和源操作数

■ m - 内存中的操作数

■ r - 寄存器操作数

■ r8,r16,r32 - 8 16 32 位寄存器

■ mm - 64 MMX 寄存器

■ m32,m64 - 内存中的 32 64 位操作数

■ ir32 - 一般的寄存器

■ imm - 立即数(常量),以字节为单位

1.2 数据交换指令

指令

描述

MOV dest, src

从寄存器、内存或立即数中加载数据。 例如:

MOV AX, 10;

MOV EBX, ESI;

MOV AL, BYTE PTR MEM;

MOV DWORD PTR MEM, 10000h

XCHG r/m, r

在寄存器之间或寄存器和内存之间交换数据。内存之间交换数据在 Intel 的指令集是不允许的

BSWAP reg32

从地位到高位交换字节。 7 0 31 24 交换, 15 8 23 16 交换。本指令从 Intel 486 处理器后开始引入。

MOVSXB r, r/m

复制符号位,并将一个字节扩展到两个字节或四个字节。例如:

MOVSXB AX, BL;

MOV EAX, BYTE PTR MEM

386 处理器后,本指令开始引入。

MOVSXW r, r/m

复制符号位,并将两个字节扩展到四个字节。例如:

MOVSXW EAX WORD PTR MEM

386 处理器后,本指令开始引入。

MOVZXB r, r/m

复制 0 位,并将一个字节扩展到两个字节或四个字节。例如:

MOVZXB AX, BL;

MOVZXB EAX, BYTE PTR MEM

386 处理器后,本指令开始引入。

MOVZXW r, r/m

复制 0 位,并将两个字节扩展到四个字节。例如:

MOVZXW EAX WORD PTR MEM

386 处理器后,本指令开始引入。

XLAT

从数据段 EBX 指向的表中中复制一个字节到 AL AL 的初始指做为偏移地址。

LEA r, m

加载有效地址,例如:

LEA EAX MEM

LEA EAX [EBX]

该命令有其“魔幻”的特征,允许高效的算术运算。例如: LEA EAX [EAX *  8 ] 指令将 EAX 的内容乘以 8 LEA EAX [EAX][EAX *4] 指令将 EAX 的内容乘以 5 LEA ECX [EAX][ESI+5] 相当于以下三条指令:

MOV ECX EAX

ADD ECX ESI

ADD ECX 5

 

注意, LEA 指令只允许被 2 4 8 乘;因此,如果你想乘以其他的数,就必须连带使用加法。

LDS r, m

从内存加载 DS:reg 对中。本指令首先加载字或双字,然后是一个字到 DS 中。

LES r, m

和上面的指令功能一样,只不过是换成了 ES:reg

LFS r, m

和上面的指令功能一样,只不过是换成了 FS:reg

LGS r, m

和上面的指令功能一样,只不过是换成了 GS:reg

LSS r, m

和上面的指令功能一样,只不过是换成了 SS:reg

根据条件设置一个字节的第一个位

SETcc r/m

检查 cc 条件。如果条件符合,字节的第一个位设置为 1 ,否则设置为 0 。这里的条件和条件跳转指令( JE JC )等是一样的。例如:

SETE AL

本指令从 Intel 3 86 处理器后开始引入。 与本指令相关的所有变体如下:

SETA/SETNBE - 如果大于则设置

SETAE/SETNB - 如果大于或等于则设置

SETB/SETNAE – 如果小于则设置

SETBE/SETNA – 如果小于或等于则设置

SETC – 如果有进位则设置

SETE/SETNZ – 如果为 0 则设置

SETG/SETNLE – 如果大于则设置

SETGE/SETNL – 如果大于或等于则设置

SETL/SETNGE – 如果小于则设置

SETLE/SETNG – 如果小于或等于则设置

SETNC – 如果为进位则设置

SETNE/SETNZ – 如果小于或相等则设置?

SETNO – 如果无溢出则设置

SETNP/SETPO – 如果没设置奇偶标志则设置

SETNS – 如果没设置符号位则设置

SETO – 如果有溢出则设置

SETP/SETPE – 如果设置了奇偶标志则设置

SETS – 如果设置了符号位则设置

LAHF

加载标志寄存器到 AH (已废弃不用)

SAHF

AH 加载到标志寄存器(已废弃不用)

根据条件搬移数据:

CMOVX dest, src

CMOVA/CMOVNBE – 大于则搬移

CMOVAE/CMOVNB – 大于或等于则搬移

CMOVB/CMOVNAE – 小于则搬移

CMOVBE/CMOVG – 小于或等于则搬移

CMOVC – 有进位则搬移

CMOVE/CMOVE – 如果为 0 则搬移

CMOVG/CMOVNLE – 大于则搬移

CMOVGE/CMOVNL – 大于或等于则搬移

CMOVL/CMOVNGE – 小于则搬移

CMOVLE/CMOVNG – 小于或等于则搬移

CMOVNC – 没有进位则搬移

CMOVNE/CMOVNZ – 小于或等与则搬移?

CMOVNO – 无溢出则搬移

CMOVNP/CMOVPO – 没设置奇偶则搬移

CMOVNS – 无符号位则搬移

CMOVO – 溢出则搬移

CMOVP/CMOVPE – 设置奇偶了则搬移

CMOVS – 有符号则设置

 

1. 3 输入 / 输出 指令

命令

描述

IN AL AX EAX , port

IN AL (AX, EAX),DX

从输入 / 输出端口加载数据到累加器中。可以使用 DX 直接寻址端口。

OUT port, AL(AX, EAX)

OUT DX, AL(AX, EAX)

输出数据到输入 / 输出端口。可以使用 DX 直接寻址端口。

[REP] INSB

[REP] INSW

[REP] IND

将由 DX 寻址的端口中的数据加载到 ES:[EDI/DI] 指向的内存中。当输出 1 2 4 个字节后, EDI/DI 修正 1 2 4 。如果带有 REP 前缀,在 CX 中的值不为 0 之前一直进行处理。

[REP] OUTSB

[REP] OUTSW

[REP] OUTSD

ES:[ESI/SI] 指向的内存数据输出到由 DX 寻址的端口。当输出 1 2 4 个字节后, ESI/SI 修正 1 2 4 。如果带有 REP 前缀,在 CX 中的值不为 0 之前一直进行处理。

 

1. 4 堆栈操作 指令

命令

描述

PUSH r/m

加载一个字或双字到堆栈中。因为堆栈不是以一个字对齐的,如果加载一个字,建议压入双字

PUSH const

加载 32 位的立即数到堆栈

PUSHA

加载 EAX EBX ECX EDX ESI EDI EBP ESP 到堆栈。本指令自 386 处理器引入

POP r/m

从堆栈弹出一个字或双字

POPA

从堆栈中弹出数据到 EAX EBX ECX EDX ESI EDI EBP ESP 。本指令自 386 处理器引入

PUSHF

加载标志寄存器到堆栈

POPF

弹出堆栈内容到标志寄存器

 

1. 5 整数算术运算 指令

命令

描述

ADD dest, src

将两个操作数相加。第一个操作数可以是寄存器或内存单元 , 第二个操作数和前面的一样,还可以是立即操作树。如果两个操作数都是内存操作数的话,指令无效。

XADD dest, src

交换两个操作数,然后行加法。自 486 后本指令引入。

ADC dest, src

带进位的加法,进位标志加在低位。

INC r/m

操作数值加 1

SUB dest, src

操作数相减。其特征和 ADD 一样。

SBB dest, src

带退位的减法。进位标志从低位减去。

DEC r/m

操作数减 1

CMP r/m, r/m

比较(两个数相减,设置相关标志寄存器的位,但不改变操作数的值)

CMPXCHG r,m,a

比较并交换。本指令接受三个操作数(寄存器操作数为源操作数,内存单元或累加器 (al,ah,eax) 为目标操作数)。如果目的和源操作数相等,则目的操作数的值用源操作数代替,而目的操作数的初试值则加载到累加器中。本指令自 486 后引入。

CMPXCHG8B

比较并交换 8 个字节。本指令自 Intel Pentium 处理器后引入。它比较 EDX:EAX 和内存中的八字节数据。

NEG r/m

反转操作数的符号

AAA

加法运算后进行 ASCII 调整。本指令调整加法后的结果为 ASCII- American Standard Code for Information Interchange (二进制未打包 BCD 码加法)。

AAS

乘法后进行 ASCII 调整。本指令调整两个未打包 BCD 码相乘的结果 1 。对于此指令,它假设 AX 中存储两个范围在 0~81 的十进制数的二进制相乘结果。操作完成后, AX 包含 ASCII 格式的两字节。它还假设最低位在 AL 中,最高位在 AH 中。 AAM 指令只有在 MUL 指令对 BCD 码进行相乘,并且结果存储在 AX 中是才有用。最后, AAM 指令调整结果,使其包含两个合乎要求的两个 BCD 未打包码。

AAD

在除法之前进行 ASCII 调整。本指令调整两个未打包 BCD 码(低位数保存在 AL 中,高位字保存在 AH 中)以使除法后的结果能生成正确的 BCD 码。本指令只有在对保存在 AX 中的未打包 BCD 码执行 DIV 操作时才有用。该指令设置 AL = AL + 10 * AH, 然后 AH = 00H The value in the AX register then equals the binary equivalent of the original unpacked, two-digit (base 10 number in registers AH and AL .

DAA

加法运算后对 AL 进行十进制调整。本操作调整两个 BCD 码相加的结果到 BCD 码,并且只在执行了对两个 BCD 码相加的 ADD 指令后才有用,处理的结果存储到 AL DAA 指令然后调整 AL 的内容使其包含两个打包了的 BCD

DAS

减法后进行十进制调整。本操作调整两个 BCD 码相减的结果到 BCD 码,并且只在执行了对两个 BCD 码相减的 SUB 指令后才有用,处理的结果存储到 AL DAS 指令然后调整 AL 的内容使其包含两个打包了的 BCD

MUL r/m

AL(AX,EAX) 与一个整数相乘。结果保存到 AX,DX:AX,EDX:EAX 中。

IMUL r/m

执行带符号的乘法运算(和 MUL 一样)。所有的操作数都看做是带符号操作数。本指令有三中形式,而且依赖于每种形式依赖于操作数的个数。其中一种形式和 MUL 一样。另外两种形式如下:

IMUL r, src; r <- r * src

IMUL dest, src, imm ; dest <- src * imm

DIV r/m(src)

执行无符号数乘法。 本指令和无符号的乘法相似。本指令执行 src 除以累加器或其扩展 (AH:AL, DX:AX,EDX:EAX) 。其结果的商防至累加器,余数放入累加器扩展中。

IDIV r/m

执行带符号的除法。 和无符号的扩展处理形式一样。

CBW

将一个字节转换成一个字。 本指令将一个字节带其符号位扩展成两个字节。它将 AL 中的一个字节扩展成一个字,然后将源操作数的符号位拷贝到 AH 中的每个位。

C WD

将一个字转换成双字。 本指令将 AX 中源操作数扩展至 DX:AX 成双字,将 AX 的第 15 位拷贝到 DX 中的每一位。

CWDE

转换一个字到双字。 本指令将源操作数 AX 带符号扩展到双字。该指令和 CWD 相似,不过只使用 EAX

C DQ

将双字 (EAX) 扩展到四字 (EDX:EAX)

ASS 脚注让我们来回想一下, ASCII 将一个字节当作一个数字,而 BCD 将半个字节当做一个数字。换句话说, AX 寄存器可以保存要么两个 ASCII 字符要么 4 BCD 数字

1. 6 逻辑运算 指令

命令

描述

AND dest, src

逻辑 AND 操作。如果相应的 src 位为 0 ,则重设 dest 的相应位也为 0

TEST dest, src

AND 一样,但是本指令不改变 dest 的值。用来检查是否有非 0 位。

OR dest, src

逻辑 OR 操作。如果 src 的相关为 1 ,则 dest 的相关位也设置为 1

XOR dest, src

异或操作。如果两个操作数的相同位的值不一样的话,这设置 dest 的相应位为 1 ,反之,如果相同的话则设置为 0

NOT dest

dest 的每一位取反操作。

 

1. 7 移位 指令

命令

描述

RCL/RCR dest, src

带进位标志向左或向右循环移位。本指令对源操作数的每个位,包括进位标志向左或向右循环的进行移位。 src 操作数可以是 CL 或立即操作数。

ROL/ROR dest, src

向左或向右循环移位。本指令和上条指令相似,只不过不使用 CF CF 位不参与移位,其原始值,不参与计算最后的结果。但 CF 的值为移位后的结果。

SAL/SAR dest, src

向左或向右算术移位。当右移位时,最高位被复制。当左移位时,最低位填充为 0 。被移出的位用来设置 CF?

SHL/SHR dest, src

向左或向右逻辑移位。相右的逻辑移位和 SAR 不同,其最高为被填充为 0

SHLD/SHRD dest, src, count

向左或向右移位,带三个操作数。和通常一样,第一个操作数可以是寄存器也可以是内存单元。第二个操作数必须是通用寄存器。第三个操作数可以是 CL ,或立即数。本操作符的本质在于首先将 dest src 结合起来,然后依据 count 的值进行移位。其结果送入 dest

 

1. 8 字符串操作 指令

命令

描述

REP

循环操作知道 ECX 的值为 0 。它有好几个变体,如 REPZ(REPS), 循环直至为 0 ZF=0 ),和 REPNZ(REPNE), 循环直到不为 0

MOVS dest, src

DE:[ESI] 指向的源地址向 ES:[EDI] 传送字节,字或双字。依据 DF 标志的不同 ESI,EDI 的值自动修正。本指令有以下变体: MOVSB(byte) ,字节传送; MOVSW(word) ,字传送 ; MOVSB(DWORD) ,双字传送。 Dest src 不必显式指定。

LODS src

加载字符串。本指令用于加载字符串到累加器中。有以下变体: lodsb,lodsw,lodsd 。当执行本指令的时候,一个字节、字、双字被加载至 AL,AX,EAX 中。 ESI 积存器依据 DF 的值自动修正 1 。不使用 REP 前缀。

STOS dest

其效果和 LODS 相反。换句话说也就是,该指令将 AL,AX,EAX 中的值传送到 dest

SCAS dest

扫描字符串。它将 dest 的值减去 AL AX EAX 中的值,并设置标志积存器的相关位。 REPNE 前缀允许查找指定的字符串。

CMPS dest, src

字符串比较。本指令拿 dest src 相应的字节,字,双字进行减法运算,并设置标志积存器相关位的值。 ESI,EDI 自动指向下一个字符。如果使用 REPE 前缀,本指令将一直比较下去直到到达字符串结尾或相应的元素不相等。如果使用 REPNE ,本指令将一直比较下去直到到达字符串结尾或相应的元素相等。

 

1. 9 标志寄存器操作 指令

命令

描述

CLC

清除进位标志。

CMC

补足进位标志,即对 CF 去反。

STC

设置进位标志。

CLD

清除方向标志,即设置 DF=0

STD

设置方向标志。

CLI

清除中断标志。可用来禁止可屏蔽硬件中断。

STI

设置中断标志。启用可屏蔽硬件中断。

CTS

重设任务切换标志。

 

1. 10 流程控制 指令

命令

描述

JMP target

本指令依据距当前地址的跳转距离和跳转到目的地址的方式有五种形式。 Windows 系统中, 32 位的段主要使用近跳转 (NEAR) 。目标地址可以通过标签直接或间接指定;换句话说,这个值可以存储在内存中也可以存储在内存单元中( JMP [EAX] )。

JMP target

跳转的另外一种形式 - 短跳转 - 占用两个字节。跳转偏移的范围为 ---128~127 。本跳转的使用有限。

段间跳转可以下面的形式出现: JMP FWORD PTR L, 这里 L 指向包含 48 位结构体的地址,该结构以 32 位的偏移开始,后接 16 位的选择子(段,调用门,任务状态段)。同时,下面的变体也是可能的: JMP FWORD ES:[EDI]

条件跳转

JA/JNBE – 大于、小于或等于则跳转。

JAE/JNB – 大于或等于则跳转。

JB/JNAE – 小于则跳转。

JBE/JNA – 小于或等于则跳转。

JC – 有进位则跳转。

JE/JZ – 相等或为 0 则跳转。

JG/JNLE – 大于则跳转。

JGE/JNL – 大于或等则跳转。

JL/JNGE – 小于则跳转。

JLE/JNG – 小于或等于则跳转。

JNC – 无进位则跳转。

JNE/JNZ – 不相等或不为 0 则跳转。

JNO – 无溢出则跳转。

JNP/JPO – 未设置奇偶标志则跳转。

JNS – 未设置符号标志则跳转。

JO – 溢出则跳转。

JP/JPE – 设置奇偶标志则跳转。

JS – 设置了符号标志则跳转。

JCXZ – 如果 CX 0 则跳转。

JECXZ - 如果 ECX 0 则跳转。

flat 内存结构中,跳转指令使用寄存器实施 32 位的跳转。

循环控制;这里列出的所有指令都依据 ECX 寄存器的值

LOOP – 如果 ECX 不为 0 则循环。

LOOPS LOOPZ) - 如果 ECX 不为 0 ZF 1 则循环。

LOOPNE LOOPNE) - 如果 ECX 不为 0 ZF 0 则循环。

CALL target

调用子过程(标签)并且将 CALL 指令下面一条指令的地址压入堆栈。在 flat 内存地址模式中,返回地址是 32 位的偏移地址。段间调用需要将选择子和偏移都压入堆栈(也就是说,是个 48 位的值,其中 16 位是选择子, 32 位为偏移值)。

RET [N]

从子过程中返回。可选的参数 N ,假设指令同时清除堆栈(释放 N 字节)。本指令有几种变体,汇编器可以根据子过程的类型 (NEAR FAR) 自由的选取使用。因此,它还可以同时显式的指定返回类型 (RETN RETE) 。在 flat 内存模式中,带 4 字节的返回地址 RETN 被默认使用。

 

1. 11 高级语言支持 指令

命令

描述

ENTER part1, part2

当进入自过程时准备堆栈。参数 part1 指定子过程中使用的本地空间,参数 part2 指定子过程的镶嵌级别。当参数 part2 0 时,不允许镶嵌(这种情况在使用 C 语言的使用会出现)。

LEAVE

退出高层子过程。它用来恢复使用 ENTER 后的原始堆栈。

BOUND r16, m16

BOUND reg32, mem32

检查数组索引的边界。本指令假设寄存器中保存了当前数组的地址,第二个操作数定义一个两个 WORD 或两个 DWORD 内存数。第一个操作数定义最小的索引值,第二个参数定义最大的索引值。如果当前的索引值超出此限制,将会生成 INT 5 指令。本指令被用于控制索引是否超出限制,对于调试有用。

 

1. 12 中断 指令

命令

描述

INT n

调用中断处理例程。本指令占用两字节。标志寄存器的值被压入堆栈,然后是返回地址的完整形式。除此之外, TF 标志被设置。上面的操作完成后,间接跳转至 n 指定的中断描述表中的指定项,该项指定了中断处理例程的地址。占用一个字节的 INT 3 指令又称为调试异常处理器,并且在调试器中被使用。

INTO

假设 OF 标志为 1, INT 4 一样。如果 OF=0, 本指令不执行任何动作。

IRET

中断返回。本指令从堆栈中接受返回地址和标志寄存器,然后从中断中返回。只有当前特权级别为 0 时,标志寄存器的特权级别位才会被修改。

 

1. 13 处理器同步 指令

命令

描述

HLT

宕机。停止指令的执行,将 CPU 切换至停止状态。通过外部中断可以将 CPU 切换到重新开始运行状态。

LOCK

声称 LOCK# 信号前缀。本指令是总线锁定前缀。它强制 CPU 对当前执行的指令产生 LOCK# 信号。在多处理器系统中,该指令阻止其他处理器的请求。

NOP

空指令,无操作。

WAIT(FWAIT)

同步协处理器。大多数协处理器指令自动处理该指令。

 

1. 14 位链处理 (Chain) 指令

命令

描述

BSF(BSR) dest, src

向前、向后扫描位。这里, dest 16 32 位的寄存器, src 可以是寄存器或内存单元。当 BSF 指令执行的时候, src 操作数从低位开始扫描。 BSR 指令从最高位开始扫描。当遇到 src 中第一个为 1 的位时将其放入 dest, 同时设置 ZF=0 。如果, src 包含 0, ZF=1,dest 的内容无定义。

BT dest, src

位测试。本指令选择 dest 指定位置的由 src 提供的位串的值,将该值存储到 CF 中。

BTC dest, src

位测试并补足。前期操作和 BT 一样,然后取反 src 相关的位。

BTR dest, src

位测试并补足。前期操作和 BT 一样,然后重设 src 相关的位。

BTS dest, src

位测试并补足。前期操作和 BT 一样,然后设置 src 相关的位。

 

1. 15 保护模式控制 指令

命令

描述

LGDT src

将由 src 指定的操作数的值加载至 GDTR Src 是个 6 字节的值(内存中)。

SGDT dest

GDTR 的值保存到内存中。

LIDT src

将由 src 指定的操作数的值加载至 IDTR

SIDT dest

IDTR 的值保存到内存中。

LLDT src

将由 src 指定的操作数的值加载至 LDTR 。本指令 16 位的源操作数到 LDTR 的段选择子字段。

SLDT dest

LDTR 的值保存到内存中。本指令的目的操作数可以是 16 字节通用寄存器或内存单元。

LMSW src

加载机器状态字( MSW )。本指令将源操作数加载值 MSW ,即 CR0 0~15 ) 。本指令的目的操作数可以是 16 字节通用寄存器或内存单元。

SMSW dest

存储 MSW 的值。

LTR src

加载任务寄存器 TR 。本指令的目的操作数可以是 16 字节通用寄存器或内存单元。该源操作数包含指向任务状态的段选择子。

STR dest

保存 TR 。本指令的目的操作数可以是 16 字节通用寄存器或内存单元。

LAR dest, src

加载访问权字节。本指令加载右 src 指定的段选择子到 dest, 而后设置 ZF

LSL dest, src

加载段限制。本指令加载右 src 指定的段选择子指定段的限制到 dest ,而后设置 ZF

ARPL r/m, r

调整段选择子的 RPL 字段。本指令比较两个段选择子,如果目的操作数的 RPL 小于源操作数的 RPL, ZF=1, 目的操作数的 RPL 字段将增加到与源操作数相同。

VERR seg

检查段是否可读。如果任务被允许读 seg 段,本指令设置 ZF=1

VERW seg

检查段是否可写。如果任务被允许写 seg 段,本指令设置 ZF=1

 

1. 16 同控制寄存器交换数据的 指令

命令

描述

MOV CRn, src

src 加载至控制寄存器 CRn

MOV dest, CRn

CRn 寄存器。

MOV DRn, src

src 加载至调试寄存器 DRn

MOV dest, DRn

DRn 寄存器。

MOV TRn, src

src 加载至调试寄存器 DRn 的测试寄存器。

MOV dest, TRn

DRn 寄存器的测试寄存器。

RDTSC

读时间印计数器。 TSC 的值存储到 EDX:EAX 寄存器对中。

 

1. 17 体系结构身份和控制 指令

命令

描述

CPUID

CPU 标识。本指令返回 CPU 的身份信息。其结果依赖于 EAX 寄存器。

如果 EAX = 0, CPU 将拜师制造商的字符串返回到 EBX,EDX,ECX 中。例如, AMD 处理器返回 AuthenticAMD ,而 Intel 处理器返回 GenuineIntel

如果 EAX = 1, 身份代码返回到 EAX 的低位中。

如果 EAX = 2, CPU 的配置参数返回到 EBX,EDX,ECX EDX 中。

RDMSR r/m

model-specific register (MSR) 读如 ECX

RDPMC

读性能监视记数器。依据 ECX 中指定的值,将两个之一中的性能监视计数器的值保存到 EDX:EAX 寄存器对中。

WRMSR r/m

MSR 。将 ECX 的值写入 MSR

SYSENTER

快速系统调用。

SYSEXIT

从系统调用中快速退出。

 

1. 18 缓存控制 指令

命令

描述

INVD

使内部缓存无效。本指令刷新 CPU 内部的高速缓存,并且同志指定功能的总线周期上的外部高速缓存刷新他们自己。内部高速缓存的内容将不再写如内存。

WBINVD

回写无效高速缓存。本指令回写所有已更改的缓存行,并且执行刷新。

INVLPG r/m

TLB 无效。本指令刷新由源操作数指定的 TLB translation lookaside buffer 转换后备缓存)。

1.2. 3 算术协处理器指令

本节主要讨论和算术协处理器相关的操作。

Intel 486 处理器发布以前,协处理器都是单独提供的。今天,协处理器已经是处理器的内建部件了。

结构和操作

算术协处理器有其自己的指令集和寄存器组。但是是其指令欲取是由处理器完成的。

算术协处理器对以下数据类型进行处理: word(16 ) short integer( 短整形, 32 ) long word(64 ) ,打包的 BCD (80 ) short real number( 短实数, 32 ) long real number( 长实数, 64 ) extend real number( 扩展的实数, 80 ) 。其中实数的格式我们在 1.1 节已经讲过了。除了一般的数字,某些协处理器操作结果会出现特殊的情况。

特殊情况

协处理器会出现的特殊的情况如下:

0 – 所有的位都为 0

0 – 符号位为 1

正无穷 – 符号位为 0 ,所有的尾数位都为 0 ,所有的指数都位为 1

负无穷 – 符号位为 1 ,所有的尾数位都为 0 ,所有的指数都位为 1

非正规数字 – 指数位都为 0

未定义数字 – 符号位为 1 ,所有的指数都位为 1 ,尾数位的第一位为 1 (对于 80 位的数字,开始的两位为 1 ),其他位都为 0

带符号 NaNs(SNaNs) - 所有的指数都位为 1 ,尾数位的第一位为 0 (对于 80 位的数字,开始的两位为 1 0 ),其他位中含有 1

Quiet NaNs(QNaNs) - 所有的指数都位为 1 ,尾数位的第一位为 0 (对于 80 位的数字,开始的两位为 1 ),尾数的其他位含有 1

和标准数字不相关的和未描述为特殊情况的不被支持的数字。

当协处理器执行操作的时候,处理器等待操作的完成。也就是说,在每条协处理器指令执行之前,汇编器自动在指令前自动生成检查协处理器是否处于忙状态的指令。如果协处理器忙,则处理器切换到等待状态。有些时候,程序员需要在协处理器指令前手动的插入 WAIT 指令。

数据寄存器

协处理器使用八个 80 位的数据寄存器作为堆栈。这些寄存器同时也被称之为协处理器堆栈。其命名为 R0~R7 ;但是,他们不能被直接访问。每个寄存器在堆栈中可以占用任何位置。和其相关的堆栈寄存器的名字为 ST(0)~ST(7)

同时也存在状态寄存器 SW ,其中的各个标志位可以使你访问操作结果。控制寄存器 CW 包含影响协处理器指令执行的位。

标记寄存器 TW 16 位,用来描述 协处理器的内容 - 每个寄存器对应 2 位。其标记反映数据寄存器的内容。标记的值描述如下: 00 用来表示非 0 01 用来表示真 0 10 用来表示特殊数字, 11 用来表示无数据。

除了上面列出的寄存器外,协处理器还有 FIP FDP 寄存器。 FIP 寄存器指定最后一个执行的指令的地址,以下指令不在其内: FTNIT, FCLEX, FLDCW, FSTCW, FSTSW, FSTSWAX, FSTEENV, FLDENV, FRSTOR, FWAITT FDP 寄存器包含指令操作数,但不包含先前的指令。

当使用协处理器指令实施计算的时候,一个很重要的职责是处理异常,也被称之为特殊情况。典型的异常是被 0 除。异常位被存储于状态寄存器。异常必须纠正结果以得到正确的结果。

异常

异常罗列如下:

不正确的结果(回绕的, rounding

无效操作数

0

下溢( tiny result

溢出 (too large result)

非常规操作数

状态字

协处理器状态字反映其所有的状态。包含以下位:

0 ,无效操作异常 IE

1, 非正规操作异常 DE

2, 0 异常 ZE

3, 溢出异常 OE

4, 下溢异常 UE

5 ,不精确(精度)异常 PE

6 ,堆栈错误异常 SF

7 ,异常摘要 SF

8 9 10 14 , 条件标志( C0,C1,C2,C3

11~13 ,指定哪个寄存器为当前的栈定

15 FPU - 也为 ES

控制字

协处理器的控制字定义使用诸多处理数字数据的方式之一。控制字的位列如下:

0 , 无效操作掩码 IM

1 , 非正规操作掩码 ZM

2, 0 掩码 ZM

3 , 溢出掩码 OM

4 , 下溢掩码 UM

5 , 不精确的结果掩码 PM

6 7 , 保留

8 9 , 精度控制 PC

10,11, 回绕控制 RC

12, 无穷大控制 IC

13~15, 保留

以下异常可以发生:

堆栈错误。结果为未定义数字。

对未定义的数进行操作。结果未定义。

SNaN 进行操作。结果为 QNaN

QNaN SNaN 之间进行比较。结果是 C0=C2=C3=1

相同符号的无限大加法或不同符号的无限大减法。结果为未定义数字。

无限大乘以 0 。结果未定义。

无限大之间相除或 0 之间相除。结果未定义。

如果除数为 0 或被除数为无限大时执行 FPREM FPREM1 指令。结果未定义, C2=0

在无限大的数字上进行三角形相关的功能。结果未定义, C2=0

Root log 操作的参数为负。结果未定义, C2=0

源寄存器为空、 QNaN SNaN 、无限大或大于 18 个字符长时执行 FBSTP 。结果未定义。

其中一个操作数为空时执行 FXCH 。结果未定义。

协处理器指令

1.19~1.23 列出了全部的 FPU 指令,并且对他们实施的操作做了概要的描述。

1.19 数据交换指令

指令

描述

FLD src

从内存中加载实数至栈 ST(0) 。这种情况下, ST(0) -> ST(1) 。内存位置可以是 32 64 80 位。 FLD ST(0) 指令复制堆栈顶。

FILD src

从内存中加载整数至栈 ST(0) 。这种情况下, ST(0) -> ST(1) 。内存位置可以是 16 32 64 位。

FBLD src

80 位的内存单元中加载 BCD ST(0)

FLDZ

ST(0) = 0

FLD1

ST(0) = 1

FLDPI

ST(0) = PI

FLDL2T

ST(0) = LOG2(10)

FLDTL2E

ST(0) = LOG2(e)

FLDLG2

ST(0) = LG(2)

FLDLN2

ST(0) = LN(2)

FST dest

从栈定往内存中写一个实数。 内存位置可以是 32 64 80 位。

FSTP dest

从栈定往内存中写一个数。 内存位置可以是 32 64 80 位。这种情况下栈顶自动弹出。

FBST dest

从栈定往内存中写一个 BCD 内存位置是 80 位。

FBSTP dest

从栈定往内存中写一个 BCD 内存位置是 80 位。这种情况下栈顶自动弹出。

FXCH st(i)

将栈顶元素也第 i 个寄存器的内容进行交换。 这种情况下栈顶自动弹出。

FCMOVc dest,src

带条件的数据拷贝。本指令拷贝 ST(i) (src) ST(0)(dest) 。以下为本指令的各种形式:

FCMOVE – zf = 1 拷贝。

FCMOVE – zf = 0 拷贝。

FCMOVB – cf = 1 拷贝。

FCMOVBE – 若小于或等于( zf = 1 CF = 1 )则 拷贝。

FCMOVBE – 若不小于或等于( zf = 0 CF = 0 )则 拷贝。

FCMOVNB – 若不小于则 拷贝 (CF=0)

FCMOVNBE – 若无序(不可比较)则 拷贝 (PF=1)

FCMOVU – 若无序(可比较)则 拷贝 (PF=0)

 

1.20 数据比较指令

指令

描述

FCOM

比较两个实数 ST(0) ST(1) 。标志位的置位方法和减法操作一样: ST(0) – ST(1)

本指令和以下的 ( 直到 FCOMI), 将对 C0,C2,C3 标志位设置如下:

ST(0) > src C0 = 0, C2 = 0, C3 = 0

ST(0) < src C0 = l, C2 = 0, C3 = 0

ST(0) = src C0 = 0, C2 = 0, C3 = 1

如果操作数是无序的(不能被比较的),则

C0 = C2 = C3 = 1

FCOM src

比较两个 ST(0) 和内存数 src 。操作数可以是 32 位或 64 位。

FCOMP src

比较两个实数 ST(0) 和内存数。栈顶 ST(0) 自动弹出。操作数可以位于寄存器或内存。

FCOMPP

比较 ST(0) ST(1) ST(0) ST(1) 从栈顶自动弹出。

FCOMI src

比较两个整数 ST(0) 和内存数 src 。操作数可以是 16 32 位。

FICOMP src

比较两个整数 ST(0) 和内存数 src 。操作数可以是 16 32 位的寄存器或内存数。栈顶 ST(0) 自动弹出。

FTST

测试 ST(0) 是否为 0

FUCOM st(i)

ST(0) ST(i) 中的数进行无序比较。

FUCOM P st(i)

ST(0) ST(i) 中的数进行无序比较。操作数栈顶 ST(0) 弹出堆栈。

FUCOMPP st(i)

ST(0) ST(i) 中的数进行无序比较。栈顶 ST(0) 弹出堆栈两次。

FCOMT src

比较并设置标志位。 四条命令 (FXAM) 将影响标志寄存器的位:

ST(0) >src ZF=0, PF=0, CF = 0

ST(0)

ST(0) =src ZF=1, PF=0, CF = 0

如果操作数是无序的,则所有的三个标志都设置为 1

FCOMIP src

比较,设置标志位, 弹出堆栈。

FUCOMI src

无序比较,设置标志位。

FUCOMIP src

无序比较,设置标志位 , 弹出堆栈。

FXAM

分析栈顶内容 。将结果保存至 C3,C3,C0

000 不支持的格式 Unsupported format

001 — NaN

010 正规数字 Normalized number

0ll 无限的 Infinity

100 Zero

101 空操作数 Blank operand

110 非正规数 Denormalized number

 

1.21 算术指令

指令

描述

FADD src

浮点数加法。

FADD ST (i), ST

ST(0) <- ST(0) + src ,这里 src 32 64 位的数 ST(i) <- ST(i) + src

FADDP ST(i), ST

浮点数加法 :ST(i) <- ST(i) + ST(0) 。栈顶 ST(0) 弹出堆栈。

FIADD src

整数数加法 :ST(0) <- ST(0) + ST(0) Src 可以为 16 32 位数。

FSUB src

浮点数减法。

FSUB ST(i), ST

浮点数减法。 ST(0) <- ST(0) – src ,这里 src 可以是 32 64 位数 ST(i) <- ST(i) – ST(0)

FSUBP ST(i), ST

浮点数减法。 ST(0) <- ST(0) – src ,这里 src 可以是 32 64 位数 ST(i) <- ST(i) – ST(0) 。栈顶 ST(0) 弹出堆栈。

FSUBR ST(i), ST

浮点数减法。 ST(0) <- ST(i) – ST(0)

FSUBRP ST(i), ST

浮点数减法。 ST(0) <- ST(i) – ST(0) 。栈顶 ST(0) 弹出堆栈。

FISUB src

整数减法 : ST(0) <- ST(0) – src, src 可以是 16 32 位数。

FISUBP src ?

整数减法 : ST(0) <- ST(0) – src, src 可以是 16 32 位数。栈顶 ST(0) 弹出堆栈。

FMUL

浮点数相乘。

FMUL ST(i)

第一种 情况: ST(0) <- ST(0) * ST(i)

FMUL ST(i) ST

二种情况: ST(0) <- ST(i) * ST(0)

第三种情况: ST(i) <- ST(i) * ST(0)

FMULP ST(i) ST(0)

浮点数相乘 :ST(i) <- ST(i) * ST(0), 栈顶 ST(0) 弹出堆栈。

FIMUL src

ST(0) 和整数相乘: ST(0) <- ST(0) * src Src 可以是 16 32 位数。

FDIV

FDIV ST(i)

ST(0) <- ST(0)/ST(1)

ST(0) <- ST(0)/ST(i)

ST(i) <- ST(0)/ST(i)

FDIV ST(i), ST

浮点数相除: ST(i) <- ST(0) / ST(i) 栈顶 ST(0) 弹出堆栈。

FDIV src

除以整数 : ST(0) <- ST(0) / src 。除数可以是 16 32 位数。

FDIVR ST(i), ST

浮点数相除: ST(0) <- ST(i) / ST(0)

FDIVRP ST(i), ST

浮点数相除: ST(0) <- ST(i) / ST(0) 栈顶 ST(0) 弹出堆栈。

FIDIVR src

用整数除: ST(0) <- src / ST(0)

FSQRT

ST(0) 的平方根。 栈顶 ST(0) 弹出堆栈。

FSCAL E

求平方: ST(0) <- ST(0) *2 ^ST(1)

FPREM

求除法的余数:

ST(0) <- ST(0) MOD(ST(1))

FPREM1

根据 IEEE 标准求除法的余数。

FUNDINT

求最接近 ST(0) 的整数 :

ST(0) <- int(ST(0))

FABS

求绝对值: ST(0) <- ABS(ST(0))

FCSH

符号反转 :ST(0) <- (-ST(0))

 

1.22 高阶三角函数指令

指令

描述

FCOS

计算 余弦 cosine ST(0) <- COS(ST(0)) ST(0) 中保存的是弧度形式的角度值。

FPTAN

计算局部的正切 tangent ST(0) 中保存的是弧度形式的角度值。正切的值保存到参数中,然后将其中的一个值压入堆栈。

FPATAN

计算反正切。 依据以下公式计算:

Arctg(ST(1) / ST(0))

计算结束后, 栈顶 ST(0) 弹出堆栈 ,结果压入堆栈。

FSIN

计算正弦 ST(0) <- sin(ST(0) ST(0) 中保存的是弧度形式的角度值。

FSINCOS

计算正弦和余弦: ST(0) <- sin(ST(0) ST(1) <- COS(ST(1)

F2XM1

计算 2^X- 1: ST(0) <-2^ST(0) – 1

FYL2X

计算 Y*LOG2(X):ST(0) = Y, ST(1) = X 。指令执行后, 栈顶 ST(0) 弹出堆栈 ,结果压入堆栈。

FYL2XP1

计算 Y*LOG2(X):ST(0) = Y, ST(1) = X 。指令执行后, 栈顶 ST(0) 弹出堆栈 ,结果压入堆栈。

 

1.23 协处理器控制指令

指令

描述

FINIT

初始化协处理器。

FNINIT

无等待初始化协处理器。

FSTSW AX

写状态字 SW AX

FSTSW dest

写状态字 SW dest(16 )

FNSTSW dest

无等待写状态字 SW dest(16 )

FLDCW src

dest 加载控制字 CW

FCLEX

检查错误条件完后, 清除 FPU 异常标志。

FNCLEX

不检查错误条件, 清除 FPU 异常标志。

FSTENV dest

检查错误条件完后, FPU 的上下文环境 (SW,CW,TAGW,FIP,FDP) 到内存。

FNSTENV dest

不检查错误条件, FPU 的上下文环境 (SW,CW,TAGW,FIP,FDP) 到内存。

FLDENV src

从内存中加载 FPU 的上下文环境 (SW,CW,TAGW,FIP,FDP)

FSAVE dest

检查错误条件完后,将 FPU 的上下文环境 (SW,CW,TAGW,FIP,FDP) 到内存。

FNSAVE dest

不检查错误条件, FPU 的上下文环境 (SW,CW,TAGW,FIP,FDP) 到内存。

FHSTOR src

恢复 FPU 的状态。

FINCSTP

增加 FPU 的堆栈指针。

FDECSTP

减少 FPU 的堆栈指针。

FFREE ST(i)

释放 FPU 寄存器。标识 ST(i) 可以自由使用。

FNOP

FPU 无动作,空指令。

WAIT(FWAIT)

指示处理器等待协处理器完成当前的指令。

 

1.2. 4 MMX 指令

MMX 体系结构

MMX 扩展指令主要用于多媒体应用程序。 MMX 的主要思想是每条指令同时处理多个数据元素。 MMX 扩展通过修改 Intel 微处理器在 Pentium P54C 中被引入,并且之后的处理器一般都存在这些指令。

MMX 扩展指令,使用新类型的打包数据 : 打包字节 (8 字节 ) ,打包字 (4 字节 ) ,打包双字 (2 个双字 ) Quadword 。正如你看到的,这些都是 64 位的数字。 MMX 扩展 8 个通用寄存器, MM0~MM7 。它们均为 64 位。实际上,这些寄存器使用 FPU 数据寄存器 R0~R7 的的低位。 MMX 指令会破坏标志寄存器和标记寄存器。因而,混合使用 MMX 指令和协处理器指令将会导致不确定的结果。也就是说,在使用 MMX 指令以前,你必须保存协处理器的上下文环境,而这在相当程度上会降低程序的运行性能。 同时,注意到 MMX 指令直接使用协处理器的寄存器而不使用栈的指针也是非常重要的。?

1.24 MMX 扩展指令

指令

描述

EMMS

清除寄存器堆栈。本指令将所有的标记位设置为 1

MOVD mm, m32/ir32

将数据传送到 MMX 寄存器的低 32 位中,将高位设置为 0

MOVD m32/ir32, mm

MMX 寄存器中传送出低位的 32 位数据。

MOVQ mm, mm/m 64

MMX 寄存器中传送数据。

MOVQ mm/m 64, mm

MMX 寄存器中传送出数据。

PACKSSDW mm, mm/m64

在有符号的情况下打包双字。本指令在有符号的情况下,将 mm 中的两个双字和 mm/m64 中的两个双字打包至 mm 中成 4 个双字。也就是说,本指令从 mm 中拷贝两个双字到 mm 的低位双字中,还将 mm/m64 中的两个双字拷贝至 mm 的高位 2 个双字中。如果某些值大于 32767 或小于 -32768 ,则 32767 -32768 将分别写入双字中。

PACKSSDB mm, mm/m64

将目的操作数(第一个操作数) 4 个有符号的字和源操作数(第二个操作数) 4 个有符号的字打包至目的操作数。如果有符号数的值超出无符号字节的范围外(即大于 255 ,小于 0 ),则相应的将 255 0 写入目的操作数。

PADDB mm, mm/m64

PADDW mm, mm/m64

PADDD mm, mm/m64

I ndividual A ddition 。源操作数和目的操作数的每个单独的数据元素(字节,字,双字)单独想加。 如果单独的加法结果超出数据类型的范围,则实施环绕,也意味着截断结果以使结果的低位数据保留 ( 也就是进位被忽略 )

PADDSB mm, mm/m64

PADDSW mm, mm/m64

带符号的打包字节(字)相加。

PADDUSB mm, mm/m64

PADDUSW mm, mm/m64

无符号的打包字节(字)相加。

PAND mm, mm/m64

执行逻辑 AND 操作。

PANDN mm, mm/m64

执行逻辑 AND NOT 操作。本指令在 4 字的目的操作数(第一个操作数)上执行基于位的逻辑 NOT 。然后,在反转后的目的操作数和 4 字的源操作数(第二个操作数)执行逻辑 AND 。如果源操作数和反转后的目的操作数的相同位都为 1 的话, AND 操作结果的每一位都设置为 1 ;否则,设置为 1 。计算结果保存至目的操作数。

PCMPEQB mm, mm/m64

PCMPEQW mm, mm/m64

PCMPEQD mm, mm/m64

打包数据的相等比较。 比较源操作数和目的操作数的各个数据元素 ( 字节,字,双字 ) 。如果两个数据元素相等,则目的操作数相应的数据元素的位将全部设置为 1(true), 否则全部位设置为 0 false )。目的操作数必须为 MMX 寄存器;源操作数可以是 MMX 寄存器或内存单元。

PCMPGTB mm, mm/m64

PCMPGTW mm, mm/m64

PCMPGTD mm, mm/m64

打包数据的大于比较。 比较源操作数和目的操作数的各个数据元素 ( 字节,字,双字 ) 。如果目的操作数比源操作数的相应数据元素大,则目的操作数相应的数据元素的位将全部设置为 1(true), 否则全部位设置为 0 false )。目的操作数必须为 MMX 寄存器;源操作数可以是 MMX 寄存器或内存单元。

PMADDWD mm, mm/m64

打包数据的相乘和相加。 本指令对目的操作数和源操作数的每个带符号的字执行乘法操作,生成 4 字节的带符号的双字。然后将目的操作数和源操作数中乘法计算得到的高低 2 个双字分别执行加法存储到目的寄存器。目的操作数必须为 MMX 寄存器;源操作数可以是 MMX 寄存器或内存单元。

PMUL HW mm, mm/m64

打包数据高位相乘。 本指令对目的操作数和源操作数的每个带符号的字执行乘法操作,生成 4 字节的带符号的双字 , 作为中间结果。每个中间结果的高端字写入目的操作数的相应位置。目的操作数必须为 MMX 寄存器;源操作数可以是 MMX 寄存器或内存单元。

PMULLW mm, mm/m64

打包数据低位相乘。本指令对目的操作数和源操作数的每个带符号的字执行乘法操作,生成 4 字节的带符号的双字 , 作为中间结果。每个中间结果的低端字写入目的操作数的相应位置。目的操作数必须为 MMX 寄存器;源操作数可以是 MMX 寄存器或内存单元。

POR mm, imm

基于位的逻辑 OR

PSHIMD mm, imm

PSHIMQ mm, imm

PSHIMW mm, imm

PSHIMW mm, irrm

PSHIMD 表示带立即操作数(计数器)的 PSLLD,PSRAD,PSRLD 指令。

PSHIMQ 表示带立即操作数(计数器)的 PSLLQ, PSRLQ 指令。

PSHIMW 表示 PSLLW, PSRAW,PSRLW 指令。

PSLLD mm, mm/m64

PSLLQ mm, mm/m64

PSLLW mm, mm/m64

打包数据的逻辑左以为操作。 本指令将目的操作数的每个单独的数据元素(字节,字,双字)分别执行用源操作数指定 count (无符号)的左移操作。移位的结果写入目的操作数。在数据左移的过程中低位的空位被清 0 。如果 count 的值大于 15 word ,31(dword),63 quadword ),则目的操作数的所有位将清 0

PSRAD mm, mm/m64

PSRAW mm, mm/m64

打包数据的算术 右移位操作。本指令将目的操作数的每个单独的数据元素(字,双字)分别执行用源操作数指定 count (无符号)的右移操作。移位的结果写入目的操作数。在数据左移的过程中高位的空位被设置为初始值的符号位值。如果 count 的值大于 15 word ,31(dword) ,则目的操作数的所有位被设置为初始值的符号位值。

PSRLD mm, mm/m64

PSRLQ mm, mm/m64
PSRLW mm, mm/m64

打包数据的逻辑右移位操作。 本指令将目的操作数的每个单独的数据元素(字,双字)分别执行用源操作数指定 count (无符号)的右移操作。移位的结果写入目的操作数。在数据左移的过程中高位的空位被清 0 。如果 count 的值大于 15 word ,31(dword) ,则目的操作数的所有位被清 0

PSUBB mm, mm/m64

PSUBD mm, mm/m64

PSUBW mm, mm/m64

打包数据的减法。 本指令将目的操作数的每个单独的数据元素(字,双字)分别执行减法操作。如果减法的结果超出的指定数据类型的范围,则结果值回绕, 也意味着截断结果以使结果的低位数据保留 ( 也就是进位被忽略 )

PSUBUSB mm, mm/m64

PSUBUSW mm, mm/m64

打包数据 无符号的减法。本指令将目的操作数的每个单独的无符号的数据元素(字,双字)分别执行减法操作。如果减法的结果超出的指定数据类型的范围,则结果为 0

PUNKCKHBW mm, mm/m64

对目的操作数和源操作数的高位 4 字节执行 interleave , 结果写入目的操作数。

PUNKCKHBD mm, mm/m64

对目的操作数和源操作数的高位两个字执行 interleave , 结果写入目的操作数。

PUNKCKHBQ mm, mm/m64

对目的操作数和源操作数的高位 双字执行 interleave , 结果写入目的操作数。

PUNPACKLBW mm, mm/m64

解包源操作数的 低位字节,然后与目的操作数的低位字节执行 interleave

PUNPACKL WD mm, mm/m64

解包源操作数的低位字,然后与目的操作数的低位字执行 interleave

PUNPACKLDQ mm, mm/m64

解包源操作数的低位 双字,然后与目的操作数的低位双字执行 interleave

PXOR mm, mm/m64

与或操作

 

MMX 新指令

Pentium 4 处理器发布后,先前列出的 MMX 指令可以授权访问 128 位寄存器 (xmm) 了。表 1.25 列出了新的 MMX 指令。

1.25 MMX 新指令

指令

描述

PADDQ xmm, xmm/m128

128 位操作数相加。

PSUBQ xmm, xmm/m128

28 位操作数相减。

PMULUDQ xmm, xmm/m128

64 位操作数相乘。其结果必须不能超过 128 位。

PSLLDQ xmm, imm

Quadword 逻辑左移。本指令对源操作数执行由 imm 指定 count 的左移操作。

PSRLDQ xmm, imm

Quadword 逻辑右移。本指令对源操作数执行由 imm 指定 count 的右移操作。

PSHUFHW xmm, xmm/m128,imm

打包数据高位字的 shuffle 操作。本指令将源操作数的高位字存储至目的操作数的相应位置。 8 位的立即操作数指定 Shuffle 的次序。

PSHUFLW xmm, xmm/m128,imm

打包数据低位字的 shuffle 操作。本指令将源操作数的低位字存储至目的操作数的相应位置。 8 位的立即操作数指定 Shuffle 的次序。

PSHUFD xmm, xmm/m128,imm

打包数据 双字的 shuffle 操作。本指令拷贝源操作数(第二个操作数)的双字,然后插入由第三个操作数指定的目的操作数的相应位置。

PUNPACKHQDQ xmm, xmm/m128

解包高位的 quadword 。本指令对源操作数和目的操作数的高位 quadword 执行 interleave 。结果写入目的操作数。

PUNPACKLQDQ xmm, xmm/m128

解包低位的 quadword 。本指令对源操作数和目的操作数的低位 quadword 执行 interleave 。结果写入目的操作数。

MOVDQ2Q xmm, mm

XMM 寄存器低位的 quadword 整数拷贝至 MMX 寄存器。

MOVQ2DQ xmm, mm

mm 寄存器的内容拷贝至 XMM 寄存器的低半部分。 MOVQ2DQ (将 quadword 整数从 XMM 寄存器拷贝至 MMX 寄存器)指令将 mm 寄存器的内容拷贝至 XMM 寄存器的低半部分。

MOVNTDQ m128, xmm

tmp 的保存双 quadword 。本指令保存打包数据。内存地址必须 16 字节对齐。

MOVDQA xmm/m128

MOVDQA xmm/m128, xmm

传送对齐的双 quadword 。本指令从内存中传送双 quadword XMM 寄存器,或相反。 XMM 之间也可以互传数据。内存地址必须 16 字节对齐。

MOVDQU xmm, xmm/m128

MOVDQU xmm/m128, xmm

传送不对齐的双 quadword 。和 MOVDQA 指令的功能一样。唯一不同时,不要求 内存地址必须 16 字节对齐。

MOVMSKPD r32, xmm

从两个打包的,双精度的,浮点数中提取符号掩码。 本指令将源操作数的符号位 (63,127) 拷贝至 r32 寄存器中。其他位被清 0

MASKMOVDQU xrrm, xmm

从源操作数(第一个操作数)选择相关的字节到 128 位的内存中。第二个操作数设置要选择字节的掩码。源操作数和掩码操作数都是 XMM 寄存器。内存地址的起始地址使用 DI/EDI DS 寄存器设置。该内存地址不用在自然分界上对齐。(存储地址的大小依赖于地址大小属性。)

 

NaN 代表” Not a Number” NaNs 就是” nonnumbers” ;它们不是实数集的一部分。浮点格式对 NaN 的编码空间在实数之上。这个空间中包含任何一个带有最大指数并且非 0 分数的情况( NaNs 的符号位被忽略)。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值