57、x64 架构机器指令全解析

x64 架构机器指令全解析

1. x64 架构指令概述

x64 架构如今拥有超 1000 条机器指令。不过别慌,很多指令仅在操作系统的保护模式下使用,还有大量用于实现浮点运算(因篇幅限制暂不展开),另有不少是用于快速加密和解密等特定功能的专用指令。

若想获取更完整权威的指令参考,可访问英特尔指令集文档: https://software.intel.com/en - us/download/intel - 64 - and - ia - 32 - architectures - sdm - combined - volumes - 1 - 2a - 2b - 2c - 2d - 3a - 3b - 3c - 3d - and - 4 ,该 PDF 文档长达 5060 页。若觉得查阅不便,也可访问 www.felixcloutier.com/x86/index.html ,此网站便于你查找所需指令,无需下载庞大文档。

2. x64 中移除的指令

在 x86 CPU 发展历程中,各代都会增减指令。以下是一些在 32 位时代学过但在 x64 中不再可用的常见指令:
- BCD 数学指令 :AAA、AAS、AAD、AAM、DAA 和 DAS。这些指令数十年前就不再必要,还占用二进制指令编码空间。
- 全压栈和全出栈指令 :PUSHA、POPA、PUSHAD 和 POPAD。如今有 16 个通用寄存器,每个 8 字节,一次移动大量数据不便,现在需逐个压栈和出栈寄存器。
- JCXZ 指令 :当 CX = 0 时跳转,这是古老的 16 位指令,其功能现由 JRCXZ(当 RCX = 0 时跳转)和 JECXZ(当 ECX = 0 时跳转)实现。
- PUSHFD 指令 :将 EFLAGS 寄存器压入栈,现用 PUSHFQ 压入 RFLAGS 寄存器。
- POPFD 指令 :从栈顶弹出双字(32 位)到 EFLAGS 寄存器,现用 POPFQ 弹出四字(64 位)到 RFLAGS 寄存器。

3. 标志位结果

每条指令都有标志位总结,示例如下:

O D I T S Z A P C  OF: 溢出标志  TF: 陷阱标志 AF: 辅助进位标志
F F F F F F F F F  DF: 方向标志 SF: 符号标志 PF: 奇偶标志
*   ? ? * * * * *  IF: 中断标志 ZF: 零标志 CF: 进位标志

这里涵盖了 9 个重要标志位:
- OF(溢出标志) :结果太大无法存入目标操作数时置 1。
- DF(方向标志) :由 STD 置 1,由 CLD 清 0。
- IF(中断标志) :由 STI 置 1,由 CLI 清 0,用户空间编程中不用,可忽略。
- TF(陷阱标志) :用于调试器,用户空间编程中不用,可忽略。
- SF(符号标志) :结果符号使目标操作数为负时置 1。
- ZF(零标志) :操作结果为 0 时置 1,非 0 时清 0。
- AF(辅助进位标志) :用于 4 位 BCD 数学运算,x64 中因 BCD 指令不可用,此标志不再使用。
- PF(奇偶标志) :结果低字节中 1 的个数为偶数时置 1,为奇数时清 0,主要用于数据通信应用。
- CF(进位标志) :加法或移位操作结果超出目标操作数时置 1,否则清 0,可通过 STC 手动置 1,通过 CLC 手动清 0。

部分指令会使某些标志位未定义,用问号表示,在标志位未通过其他指令明确前,勿测试或使用其状态。

4. 大小指定符

在汇编语言中访问内存数据时,存在确定操作内存数据大小的问题。例如 inc [rdi + 4] ,无法判断是对字节、字、双字还是四字进行递增操作,NASM 会报错。

NASM 识别 BYTE、WORD、DWORD 和 QWORD 等大小指定符,分别表示 8、16、32 和 64 字节。如 inc qword [rdi + 4] 明确是对 64 位值递增。

对于单操作数的 x64 指令(如 INC、DEC、NOT、NEG、SHR、SHL、ROR 和 ROL),操作内存时需大小指定符。对于双操作数指令:
- 若一个操作数是内存访问,另一个是寄存器,NASM 会根据寄存器大小推断访问大小,如 mov [rdi + rbx * 8], rcx ,因 RCX 是 64 位寄存器,会将 64 位数据从 RCX 移到 [RDI + RBX * 8] 开始的 8 字节处。
- 若一个操作数在内存,另一个是常量,需大小指定符,如 mov word [rdi], 42 表示将 42 复制到 RDI 地址开始的两个字节内存中。

5. 部分指令索引
指令 参考页 文本页 CPU
ADC
ADD
AND
BT 386+
CALL
CLC 此处仅提及
CLD
CMP
DEC
INC
INT
IRET
J?
JECXZ x64+
JMP
JRCXZ x64+
LEA
LOOP
LOOPNZ/LOOPNE
LOOPZ/LOOPE
MOV
MUL
NEG
NOP 此处仅提及
NOT
OR
POP
POPF
POPFQ x64+
PUSH
PUSHF
PUSHFQ x64+
RET
ROL
ROR
SBB 此处仅提及
SHL
SHR
STC 此处仅提及
STD
STOS
SUB
SYSCALL x64+
XCHG
XLAT
XOR
6. 部分指令详解
6.1 ADC:带进位的算术加法
  • 受影响标志位
O D I T S Z A P C  OF: 溢出标志  TF: 陷阱标志 AF: 辅助进位标志
F F F F F F F F F  DF: 方向标志 SF: 符号标志 PF: 奇偶标志
*       * * * * *  IF: 中断标志 ZF: 零标志 CF: 进位标志
  • 合法形式
ADC r/m8,i8
ADC r/m16,i16
ADC r/m32,i32      386+
ADC r/m64,i32      x64+   注意: ADC r/m64X,i64 无效!
ADC r/m8,r8
ADC r/m16,r16
ADC r/m32,r32      386+
ADC r/m64,r64      x64+
ADC r/m16,i8
ADC r/m32,i8
ADC r/m64,i8       x64+
ADC r8,r/m8
ADC r16,r/m16
ADC r32,r/m32      386+
ADC r64,r/m64      x64+
ADC AL,i8
ADC AX,i16
ADC EAX,i32        386+
ADC RAX,i32        x64+   注意: ADC RAX,i64 无效!
  • 示例
ADC BX,DI
ADC EAX,5
ADC AX,0FFFFH
ADC AL,42H
ADC RBP,17H
ADC QWORD [RBX+RSI+Inset],5
  • 说明 :ADC 将源操作数和进位标志加到目标操作数,结果替换目标操作数,是算术加法,进位用于多精度加法。若结果无法存入目标操作数,进位标志置 1。
6.2 ADD:算术加法
  • 受影响标志位
O D I T S Z A P C  OF: 溢出标志  TF: 陷阱标志 AF: 辅助进位标志
F F F F F F F F F  DF: 方向标志 SF: 符号标志 PF: 奇偶标志
*       * * * * *  IF: 中断标志 ZF: 零标志 CF: 进位标志
  • 合法形式
ADD r/m8,i8
ADD r/m16,i16
ADD r/m32,i32       386+
ADD r/m64,i32       x64+  注意: ADD r/m64,i64 无效!
ADD r/m16,i8
ADD r/m32,i8        386+
ADD r/m64,i8        x64+
ADD r/m8,r8
ADD r/m16,r16
ADD r/m32,r32       386+
ADD r/m64,r64       x64+
ADD r8,r/m8
ADD r16,r/m16
ADD r32,r/m32       386+
ADD r64,r/m64       x64+
ADD AL,i8
ADD AX,i16
ADD EAX,i32         386+
ADD RAX,i32         x64+  注意: ADD RAX,i64 无效!
  • 示例
ADD BX,DI
ADD AX,0FFFFH
ADD AL,42H
ADD [EDI],EAX
AND QWORD [RAX],7BH
  • 说明 :ADD 将源操作数加到目标操作数,结果替换目标操作数,是算术加法,不考虑进位标志(考虑进位用 ADC)。若结果无法存入目标操作数,进位标志置 1。
6.3 AND:逻辑与
  • 受影响标志位
O D I T S Z A P C  OF: 溢出标志  TF: 陷阱标志 AF: 辅助进位标志
F F F F F F F F F  DF: 方向标志 SF: 符号标志 PF: 奇偶标志
*       * * ? * *  IF: 中断标志 ZF: 零标志 CF: 进位标志
  • 合法形式
AND r/m8,i8
AND r/m16,i16
AND r/m32,i32      386+
AND r/m64,i32      x64+   注意: AND r/m64,i64 无效!
AND r/m16,i8
AND r/m32,i8       386+
AND r/m64,i8       x64+
AND r/m8,r8
AND r/m16,r16
AND r/m32,r32      386+
AND r/m64,r64      x64+
AND r8,r/m8
AND r16,r/m16
AND r32,r/m32      386+
AND r64,r/m64      x64+
AND AL,i8
AND AX,i16
AND EAX,i32        386+
AND RAX,i32        x64+ 注意: AND RAX,i64 无效!
  • 示例
AND BX,DI
AND EAX,5
AND AX,0FFFFH
AND AL,42H
AND [BP+SI],DX
AND QWORD [RDI],42
AND QWORD [RBX],0B80000H
  • 说明 :AND 对两个操作数逐位进行逻辑与运算,结果替换目标操作数。该操作使辅助进位标志未定义,CF 和 OF 清 0,其他受影响标志位根据运算结果设置。
6.4 BT:位测试
  • 受影响标志位
O D I T S Z A P C  OF: 溢出标志  TF: 陷阱标志 AF: 辅助进位标志
F F F F F F F F F  DF: 方向标志 SF: 符号标志 PF: 奇偶标志
                *  IF: 中断标志 ZF: 零标志 CF: 进位标志
  • 合法形式
BT r/m16,r16       386+
BT r/m32,r32       386+
BT r/m64,r64       x64+
BT r/m16,i8        386+
BT r/m32,i8        386+
BT r/m64,i8        x64+
  • 示例
BT AX,CX
BT EAX,EDX
BT RAX,5
BT [RAX+RDX],RCX
  • 说明 :BT 将左操作数的指定单一位复制到进位标志,可用于测试或通过移位/旋转指令反馈。右操作数指定复制的位,不改变操作数。若右操作数是 8 位立即值,指定复制的位编号;若超出左操作数大小,按左操作数大小取模。若右操作数不是立即值,还指定内存引用偏移,较复杂,可查阅完整汇编语言参考。
6.5 CALL:调用过程
  • 受影响标志位
O D I T S Z A P C  OF: 溢出标志  TF: 陷阱标志 AF: 辅助进位标志
F F F F F F F F F  DF: 方向标志 SF: 符号标志 PF: 奇偶标志
     <无>        IF: 中断标志 ZF: 零标志 CF: 进位标志
  • 合法形式
CALL d16           x64 中无效
CALL d32           x64 之前无效
CALL r/m16         x64 中无效
CALL r/m32         x64 中无效
CALL r/m64         x64 之前无效
  • 示例
CALL DoSomething
CALL RAX
CALL QWORD [EBX+ECX+16]
  • 说明 :CALL 将控制权转移到过程地址,转移前将下一条指令地址压入栈,以便 RET 指令返回。除调用定义的标签,还可转移到 64 位通用寄存器或内存中的地址,CALL m64 用于创建过程地址跳转表。d32 是 32 位无符号位移,在 64 位长模式下符号扩展为 64 位。CALL 还有与操作系统保护机制相关的变体,可查阅高级资料。
7. 指令操作数说明

为更好理解指令,对操作数的含义进行说明:
| 操作数 | 含义 |
| — | — |
| m8 | 8 位内存数据 |
| m16 | 16 位内存数据 |
| m32 | 32 位内存数据 |
| m64 | 64 位内存数据 |
| i8 | 8 位立即数据 |
| i16 | 16 位立即数据 |
| i32 | 32 位立即数据 |
| i64 | 64 位立即数据 |
| d8 | 8 位有符号位移 |
| d16 | 16 位有符号位移 |
| d32 | 32 位无符号位移(无 64 位位移) |
| r8 | AL、AH、BL、BH、CL、CH、DL、DH |
| r16 | AX、BX、CX、DX、BP、SP、SI、DI |
| r32 | EAX、EBX、ECX、EDX、EBP、ESP、ESI、EDI |
| r64 | RAX、RBX、RCX、RDX、RBP、RSP、RSI、RDI、R8、R9、R10、R11、R12、R13、R14、R15 |

8. 指令使用流程示例

ADD 指令为例,展示其在实际使用中的流程:

graph TD;
    A[开始] --> B[确定操作数类型和大小];
    B --> C{操作数是否符合合法形式};
    C -- 是 --> D[执行 ADD 指令];
    C -- 否 --> E[调整操作数或指令形式];
    E --> C;
    D --> F[检查标志位状态];
    F --> G[根据标志位进行后续操作];
    G --> H[结束];
9. 指令使用注意事项
  • 大小指定符使用 :在操作内存数据时,务必根据指令和操作数情况正确使用大小指定符,避免 NASM 报错。例如单操作数指令操作内存时,一定要添加合适的大小指定符。
  • 标志位状态 :部分指令会影响标志位状态,有些还会使标志位未定义。在使用标志位进行判断或操作前,要确保标志位处于确定状态。
  • 指令兼容性 :不同 CPU 版本对指令的支持不同,如 386+ 表示从 386 及以上 CPU 支持, x64+ 表示从 x64 及以上 CPU 支持,使用时要根据实际 CPU 情况选择合适的指令。
10. 常见指令使用场景分析
  • 算术运算指令(ADC、ADD) :在进行多精度加法时,可使用 ADC 指令结合进位标志实现;普通加法运算则使用 ADD 指令。例如在处理大整数加法时,可利用 ADC 逐位相加并处理进位。
  • 逻辑运算指令(AND) :常用于位掩码操作,如提取特定位信息。例如 AND EAX, 0x000000FF 可提取 EAX 寄存器的低 8 位。
  • 位测试指令(BT) :可用于检查某个二进制数中特定位置的位状态,如 BT RAX, 5 可检查 RAX 寄存器中第 5 位的状态。
  • 调用过程指令(CALL) :在程序中调用子过程或函数时使用,可实现代码的模块化和复用。例如 CALL DoSomething 可调用名为 DoSomething 的子过程。
11. 总结

x64 架构的机器指令丰富多样,理解和掌握这些指令对于编写高效的汇编语言程序至关重要。通过了解指令的功能、合法形式、受影响标志位以及操作数的含义,能够正确使用指令并处理各种情况。同时,要注意大小指定符的使用、标志位状态和指令兼容性等问题,根据不同的使用场景选择合适的指令,以实现程序的特定功能。在实际编程中,可结合具体需求,灵活运用这些指令,提高程序的性能和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值