x86-64汇编从入门到精通
x86-64汇编从入门到精通
x86-64(也称AMD64或Intel 64)是目前个人电脑和服务器领域最主流的指令集架构。无论是进行底层性能优化、操作系统开发、逆向工程,还是深入理解计算机体系结构,掌握x86-64汇编都是一项关键技能。本文将系统性地带你从零基础走向实战。
第一部分:为什么学习x86-64汇编?
汇编语言是连接软件与硬件的桥梁。学习x86-64汇编的价值体现在多个层面:首先,它让你能够写出极致高性能的代码,在关键路径上榨干硬件潜能;其次,它是安全研究和逆向工程的必备工具;最后,深入理解汇编能让你写出更高质量的C/C++/Rust代码,因为你清楚编译器在背后做了什么。
x86-64架构统治了数十年桌面和服务器市场,掌握了它就能深入理解绝大多数生产环境的底层运行机制。
第二部分:前置知识与环境准备
2.1 前置知识要求
学习本系列内容前,建议具备以下基础:
- 能看懂C语言编写的程序
- 了解计算机体系结构的基本概念(寄存器、内存、栈等)
- 能够简单使用命令行进行操作
2.2 开发环境搭建
Linux环境(推荐):
- 编译器:GCC(
gcc)或Clang - 汇编器:GAS(GNU Assembler,
as)或NASM - 调试器:GDB
- 反汇编工具:objdump
macOS环境:
- 编译器:Clang(Xcode自带)
- 汇编器:AS(GNU assembler,随Xcode安装)
- 调试器:LLDB
Windows环境:
- 可使用MinGW、Cygwin或WSL2(推荐)
- MASM(微软宏汇编器)或NASM
验证环境:
gcc--versionas--versiongdb--version第三部分:x86-64编程模型
3.1 寄存器一览
x86-64的寄存器体系需要重点掌握:
通用寄存器(64位):
| 64位 | 32位 | 16位 | 8位(低) | 用途 |
|---|---|---|---|---|
| RAX | EAX | AX | AL | 累加器,返回值 |
| RBX | EBX | BX | BL | 被调用者保存 |
| RCX | ECX | CX | CL | 计数器,第4个参数 |
| RDX | EDX | DX | DL | 第3个参数 |
| RSI | ESI | SI | SIL | 第2个参数 |
| RDI | EDI | DI | DIL | 第1个参数 |
| RBP | EBP | BP | BPL | 帧指针(被调用者保存) |
| RSP | ESP | SP | SPL | 栈指针 |
| R8-R15 | R8D-R15D | R8W-R15W | R8B-R15B | 扩展寄存器 |
特殊寄存器:
| 寄存器 | 用途 |
|---|---|
| RIP | 指令指针(程序计数器) |
| RFLAGS | 状态标志寄存器 |
| XMM0-XMM15 | 128位SIMD寄存器(浮点/向量) |
| YMM0-YMM15 | 256位SIMD寄存器(AVX) |
| ZMM0-ZMM15 | 512位SIMD寄存器(AVX-512) |
宽度变体:
- 写32位寄存器(EAX)会自动将高32位清零
- 写16位/8位寄存器不影响高48/56位
3.2 System V AMD64 ABI调用约定
理解调用约定是编写正确汇编函数的关键(Linux/macOS适用):
参数传递:
- 第1个参数:RDI
- 第2个参数:RSI
- 第3个参数:RDX
- 第4个参数:RCX(Linux)/ R10(macOS)
- 第5个参数:R8
- 第6个参数:R9
- 第7个及以后参数:通过栈传递
- 浮点/SIMD参数:XMM0-XMM7
- 返回值:RAX(整数),XMM0(浮点)
保存规则:
- 被调用者保存(需在函数中保护):RBX, RBP, R12-R15
- 调用者保存(不用保护):RAX, RCX, RDX, RDI, RSI, R8-R11, XMM0-XMM15
栈规则:执行CALL前RSP必须16字节对齐
3.3 与AArch64的主要区别
| 特性 | x86-64 | AArch64 |
|---|---|---|
| 寄存器数量 | 16个通用寄存器 | 31个通用寄存器 |
| 指令编码 | 变长(1-15字节) | 固定32位 |
| 栈增长方向 | 向下(地址减小) | 向下(地址减小) |
| 参数传递 | RDI, RSI, RDX, RCX, R8, R9 | X0-X7 |
| 返回值 | RAX | X0 |
| 帧指针 | RBP(可选) | X29(固定) |
| 分支指令 | JMP, Jcc | B, B.cond |
第四部分:x86-64指令集入门
4.1 指令格式概览
x86指令采用变长编码,典型格式为:
[opcode] [dest], [src1], [src2]示例(AT&T语法):
movq %rax, %rbx ; RBX = RAX addq $10, %rax ; RAX += 10示例(Intel语法):
mov rbx, rax ; RBX = RAX add rax, 10 ; RAX += 10两种语法对比:
| AT&T语法 | Intel语法 |
|---|---|
| 源操作数在前,目标在后 | 目标在前,源在后 |
寄存器前加% | 寄存器不加% |
立即数前加$ | 立即数不加$ |
内存地址用() | 内存地址用[] |
movl $1, (%rax) | mov dword [rax], 1 |
本文主要使用Intel语法(更直观)。
4.2 寻址模式
| 模式 | 示例 | 有效地址 |
|---|---|---|
| 立即数 | mov rax, 42 | 直接使用42 |
| 寄存器 | mov rax, rbx | RBX的值 |
| 直接内存 | mov rax, [0x1000] | 地址0x1000的内存 |
| 寄存器间接 | mov rax, [rbx] | RBX指向的内存 |
| 基址+偏移 | mov rax, [rbx+16] | RBX+16 |
| 基址+索引 | mov rax, [rbx+rcx*8] | RBX+RCX*8 |
| 基址+索引+偏移 | mov rax, [rbx+rcx*4+8] | RBX+RCX*4+8 |
| RIP相对 | mov rax, [rip+offset] | RIP+offset |
4.3 数据宽度后缀
x86指令需要指明操作数宽度:
| 后缀 | 宽度 | 示例 |
|---|---|---|
| b | 8位(字节) | movb al, bl |
| w | 16位(字) | movw ax, bx |
| l | 32位(双字) | movl eax, ebx |
| q | 64位(四字) | movq rax, rbx |
第五部分:常用指令大全
5.1 数据传送指令
| 指令 | 描述 | 示例 |
|---|---|---|
| MOV | 传送数据 | mov rax, rbx |
| MOVZX | 零扩展传送 | movzx rax, byte [rsi] |
| MOVSX | 符号扩展传送 | movsx rax, byte [rsi] |
| MOVSXD | 符号扩展32位到64位 | movsxd rax, eax |
| LEA | 加载有效地址 | lea rax, [rbx+rcx*4] |
| XCHG | 交换数据 | xchg rax, rbx |
| PUSH | 压栈 | push rax |
| POP | 出栈 | pop rax |
| PUSHF | 压入标志寄存器 | pushf |
| POPF | 弹出标志寄存器 | popf |
LEA的妙用:不访问内存,只计算地址,常用于快速算术运算:
lea rax, [rcx+rcx*4] ; RAX = RCX * 5 lea rax, [rax+rax*2] ; RAX = RAX * 35.2 算术运算指令
| 指令 | 描述 | 示例 |
|---|---|---|
| ADD | 加法 | add rax, rbx |
| ADC | 带进位加法 | adc rax, rbx |
| SUB | 减法 | sub rax, rbx |
| SBB | 带借位减法 | sbb rax, rbx |
| INC | 自增1 | inc rax |
| DEC | 自减1 | dec rax |
| IMUL | 有符号乘法 | imul rax, rbx |
| MUL | 无符号乘法 | mul rbx |
| IDIV | 有符号除法 | idiv rbx |
| DIV | 无符号除法 | div rbx |
| NEG | 取负 | neg rax |
| CMP | 比较 | cmp rax, rbx |
注意:MUL和DIV使用RAX和RDX:
MUL rbx:RDX:RAX = RAX * RBXDIV rbx:RAX = RDX:RAX / RBX,RDX = 余数
5.3 逻辑运算指令
| 指令 | 描述 | 示例 |
|---|---|---|
| AND | 按位与 | and rax, rbx |
| OR | 按位或 | or rax, rbx |
| XOR | 按位异或 | xor rax, rax |
| NOT | 按位取反 | not rax |
| TEST | 测试(与AND同,不写结果) | test rax, rax |
| SHL | 逻辑左移 | shl rax, 2 |
| SHR | 逻辑右移 | shr rax, 2 |
| SAR | 算术右移(符号扩展) | sar rax, 2 |
| ROL | 循环左移 | rol rax, 1 |
| ROR | 循环右移 | ror rax, 1 |
5.4 分支与跳转指令
| 指令 | 描述 | 示例 |
|---|---|---|
| JMP | 无条件跳转 | jmp label |
| CALL | 调用函数 | call func |
| RET | 从函数返回 | ret |
| JE/JZ | 相等/零跳转 | je label |
| JNE/JNZ | 不相等/非零跳转 | jne label |
| JG/JNLE | 有符号大于跳转 | jg label |
| JGE/JNL | 有符号大于等于跳转 | jge label |
| JL/JNGE | 有符号小于跳转 | jl label |
| JLE/JNG | 有符号小于等于跳转 | jle label |
| JA/JNBE | 无符号大于跳转 | ja label |
| JAE/JNB | 无符号大于等于跳转 | jae label |
| JB/JNAE | 无符号小于跳转 | jb label |
| JBE/JNA | 无符号小于等于跳转 | jbe label |
条件跳转的反向:了解对立条件便于代码优化
| 条件 | 对立条件 |
|---|---|
| JE (相等) | JNE (不相等) |
| JG (有符号大于) | JLE (有符号小于等于) |
| JL (有符号小于) | JGE (有符号大于等于) |
| JA (无符号大于) | JBE (无符号小于等于) |
| JB (无符号小于) | JAE (无符号大于等于) |
5.5 标志寄存器与条件码
RFLAGS寄存器中的关键标志位:
| 标志 | 含义 | 设置条件 |
|---|---|---|
| ZF(零标志) | 结果为零 | 运算结果等于0 |
| SF(符号标志) | 结果为负 | 最高位为1 |
| CF(进位标志) | 无符号溢出 | 运算产生进位/借位 |
| OF(溢出标志) | 有符号溢出 | 符号位错误 |
| PF(奇偶标志) | 低8位含偶数个1 | 偶数个1 |
5.6 位操作与条件传送指令
| 指令 | 描述 | 示例 |
|---|---|---|
| BSWAP | 字节序反转 | bswap rax |
| BT | 位测试 | bt rax, 3 |
| BTS | 位测试并置1 | bts rax, 3 |
| BTR | 位测试并清零 | btr rax, 3 |
| BTC | 位测试并取反 | btc rax, 3 |
| CMOVcc | 条件传送 | cmovg rax, rbx |
| SETcc | 条件设置 | setg al |
CMOV示例:
cmp rax, rbx cmovl rax, rbx ; if (rax < rbx) rax = rbx(取最大值)5.7 栈操作指令
| 指令 | 描述 | 等效操作 |
|---|---|---|
| PUSH reg | 压栈 | sub rsp, 8; mov [rsp], reg |
| POP reg | 出栈 | mov reg, [rsp]; add rsp, 8 |
| PUSHQ imm | 压入立即数 | sub rsp, 8; mov [rsp], imm |
| ENTER | 创建栈帧 | 少用 |
| LEAVE | 销毁栈帧 | mov rsp, rbp; pop rbp |
第六部分:第一个汇编程序
6.1 Hello World(Linux)
文件:hello.s
.section .text .globl _start _start: ; write(1, msg, 14) mov $1, %rax ; 系统调用号1 = write mov $1, %rdi ; 文件描述符1 = stdout lea msg(%rip), %rsi ; 消息地址 mov $14, %rdx ; 消息长度 syscall ; 系统调用 ; exit(0) mov $60, %rax ; 系统调用号60 = exit xor %rdi, %rdi ; 返回值0 syscall .section .data msg: .ascii "Hello, x86-64!\\n"编译与运行:
as-ohello.o hello.s ld-ohello hello.o ./hello6.2 简单加法函数
汇编文件 add.s(Linux/macOS):
.section .text .globl add add: ; int add(int a, int b) -> a在RDI, b在RSI mov %edi, %eax ; EAX = a add %esi, %eax ; EAX += b retC文件 main.c:
#include<stdio.h>externintadd(inta,intb);intmain(){intresult=add(3,5);printf("Result: %d\\n",result);return0;}编译与运行:
gcc-cadd.s-oadd.o gcc-oprog main.c add.o ./prog第七部分:栈帧管理
7.1 函数入口与出口模式
标准函数序言(Prologue):
func_name: push rbp ; 保存旧的帧指针 mov rbp, rsp ; 设置新的帧指针 sub rsp, frame_size ; 分配局部变量空间标准函数尾声(Epilogue):
mov rsp, rbp ; 释放局部变量空间 pop rbp ; 恢复帧指针 ret7.2 局部变量访问
func: push rbp mov rbp, rsp sub rsp, 32 ; 分配32字节局部空间 mov dword [rbp-4], 10 ; 局部变量1 = 10 mov dword [rbp-8], 20 ; 局部变量2 = 20 mov eax, [rbp-4] ; 加载局部变量1 add eax, [rbp-8] ; 加上局部变量2 mov rsp, rbp pop rbp ret7.3 保存被调用者保存寄存器
func: push rbp mov rbp, rsp sub rsp, 64 push rbx ; 保存被调用者保存寄存器 push r12 push r13 push r14 push r15 ; 使用RBX, R12-R15寄存器... pop r15 ; 恢复(注意顺序相反) pop r14 pop r13 pop r12 pop rbx mov rsp, rbp pop rbp ret第八部分:SIMD与浮点运算
8.1 XMM/YMM/ZMM寄存器
x86-64支持多种SIMD扩展:
| 扩展 | 寄存器 | 宽度 | 数据类型 |
|---|---|---|---|
| SSE | XMM0-XMM15 | 128位 | 单精度浮点(4个) |
| SSE2 | XMM0-XMM15 | 128位 | 双精度浮点(2个) |
| AVX | YMM0-YMM15 | 256位 | 8个单精度/4个双精度 |
| AVX-512 | ZMM0-ZMM15 | 512位 | 16个单精度/8个双精度 |
8.2 浮点运算指令
| 指令 | 描述 | 示例 |
|---|---|---|
| MOVSS | 加载/存储单精度 | movss xmm0, [mem] |
| MOVSD | 加载/存储双精度 | movsd xmm0, [mem] |
| ADDSS | 单精度加法 | addss xmm0, xmm1 |
| ADDSD | 双精度加法 | addsd xmm0, xmm1 |
| SUBSS | 单精度减法 | subss xmm0, xmm1 |
| SUBSD | 双精度减法 | subsd xmm0, xmm1 |
| MULSS | 单精度乘法 | mulss xmm0, xmm1 |
| MULSD | 双精度乘法 | mulsd xmm0, xmm1 |
| DIVSS | 单精度除法 | divss xmm0, xmm1 |
| DIVSD | 双精度除法 | divsd xmm0, xmm1 |
| SQRTSS | 单精度平方根 | sqrtss xmm0, xmm1 |
| SQRTSD | 双精度平方根 | sqrtsd xmm0, xmm1 |
| CVTSI2SS | 整数转单精度浮点 | cvtsi2ss xmm0, eax |
| CVTSS2SI | 单精度浮点转整数 | cvtss2si eax, xmm0 |
| CVTSI2SD | 整数转双精度浮点 | cvtsi2sd xmm0, eax |
| CVTSD2SI | 双精度浮点转整数 | cvtsd2si eax, xmm0 |
| UCOMISS | 比较单精度 | ucomiss xmm0, xmm1 |
| UCOMISD | 比较双精度 | ucomisd xmm0, xmm1 |
8.3 浮点条件分支
ucomisd xmm0, xmm1 ; 比较xmm0和xmm1 ja greater ; 无符号大于(实际用于浮点比较) jb less je equal8.4 SSE/AVX向量运算
128位SSE向量示例:
movaps xmm0, [rsi] ; 加载4个单精度到xmm0 movaps xmm1, [rdi] ; 加载4个单精度到xmm1 addps xmm0, xmm1 ; 4个单精度同时相加 movaps [rdx], xmm0 ; 存储结果256位AVX示例:
vmovaps ymm0, [rsi] ; 加载8个单精度到ymm0 vmovaps ymm1, [rdi] ; 加载8个单精度到ymm1 vaddps ymm0, ymm0, ymm1 ; 8个单精度同时相加 vmovaps [rdx], ymm0 ; 存储结果向量点积示例:
xorps xmm0, xmm0 ; 清零累加器 mov rcx, 8 ; 循环8次 loop: movss xmm1, [rsi] ; 加载a[i] mulss xmm1, [rdi] ; a[i] * b[i] addss xmm0, xmm1 ; sum += 乘积 add rsi, 4 add rdi, 4 loop loop ret第九部分:条件分支与循环
9.1 if-else结构
C代码:
if(a>b){result=a;}else{result=b;}对应汇编:
cmp eax, ebx jle else ; if (a <= b) goto else mov ecx, eax ; result = a jmp done else: mov ecx, ebx ; result = b done: mov eax, ecx ; 返回result9.2 for循环
C代码:
intsum=0;for(inti=0;i<100;i++){sum+=i;}对应汇编:
xor eax, eax ; sum = 0 xor ecx, ecx ; i = 0 loop_start: cmp ecx, 100 jge loop_end ; if i >= 100, exit add eax, ecx ; sum += i inc ecx ; i++ jmp loop_start loop_end: ret9.3 while循环
C代码:
while(n>0){result+=n;n--;}对应汇编:
loop_start: cmp rdi, 0 jle loop_end add rax, rdi dec rdi jmp loop_start loop_end: ret9.4 循环优化:使用LOOP指令
LOOP指令等价于dec rcx; jnz target:
mov rcx, 100 loop_start: ; 循环体 loop loop_start注意:LOOP在现代CPU上性能通常不如显式的DEC+JNZ,不推荐在性能敏感代码中使用。
第十部分:实战示例
10.1 字符串长度计算
.globl strlen strlen: xor rax, rax ; len = 0 mov rcx, -1 ; 计数器 xor al, al ; 搜索NULL repne scasb ; 扫描字符串 not rcx ; 补码 dec rcx ; 减去终止符 mov rax, rcx ret10.2 数组求和
.globl array_sum ; int64_t array_sum(int64_t *arr, int64_t len) array_sum: xor rax, rax ; sum = 0 xor rcx, rcx ; i = 0 loop: cmp rcx, rsi jge done add rax, [rdi+rcx*8] ; sum += arr[i] inc rcx jmp loop done: ret10.3 冒泡排序
.globl bubble_sort ; void bubble_sort(int *arr, int n) bubble_sort: push rbp mov rbp, rsp push rbx mov rcx, rsi ; outer = n dec rcx ; outer = n-1 outer_loop: cmp rcx, 0 jle done xor rdx, rdx ; i = 0 inner_loop: cmp rdx, rcx jge next_outer mov eax, [rdi+rdx*4] ; arr[i] mov ebx, [rdi+rdx*4+4] ; arr[i+1] cmp eax, ebx jle no_swap mov [rdi+rdx*4], ebx ; 交换 mov [rdi+rdx*4+4], eax no_swap: inc rdx jmp inner_loop next_outer: dec rcx jmp outer_loop done: pop rbx pop rbp ret10.4 SIMD优化数组点积
.globl dot_product ; float dot_product(float *a, float *b, int len) dot_product: xorps xmm0, xmm0 ; sum = 0 xor rax, rax ; i = 0 loop: cmp rax, rdx jge done movss xmm1, [rdi+rax*4] mulss xmm1, [rsi+rax*4] addss xmm0, xmm1 inc rax jmp loop done: ret ; SSE向量化优化版本 .globl dot_product_sse dot_product_sse: xorps xmm0, xmm0 ; 累加器清零 xor rax, rax ; i = 0 mov rcx, rdx shr rcx, 2 ; 每次处理4个 jz remainder loop4: movaps xmm1, [rdi+rax*4] mulps xmm1, [rsi+rax*4] addps xmm0, xmm1 add rax, 4 loop loop4 ; 水平相加 haddps xmm0, xmm0 haddps xmm0, xmm0 ; 处理剩余元素 remainder: ; ... 处理余数 ret第十一部分:系统调用(Linux)
11.1 Linux系统调用速查表
x86-64系统调用使用syscall指令,参数通过寄存器传递:
| 参数 | 寄存器 |
|---|---|
| 系统调用号 | RAX |
| 第1个参数 | RDI |
| 第2个参数 | RSI |
| 第3个参数 | RDX |
| 第4个参数 | R10 |
| 第5个参数 | R8 |
| 第6个参数 | R9 |
| 返回值 | RAX |
常用系统调用:
| 调用名 | RAX值 | 说明 |
|---|---|---|
| read | 0 | 读取文件 |
| write | 1 | 写入文件 |
| open | 2 | 打开文件 |
| close | 3 | 关闭文件 |
| stat | 4 | 获取文件状态 |
| fstat | 5 | 获取文件状态(文件描述符) |
| mmap | 9 | 内存映射 |
| mprotect | 10 | 修改内存保护 |
| brk | 12 | 调整数据段大小 |
| socket | 41 | 创建socket |
| connect | 42 | 连接socket |
| sendto | 44 | 发送数据 |
| recvfrom | 45 | 接收数据 |
| exit | 60 | 退出进程 |
| getpid | 39 | 获取进程ID |
| fork | 57 | 创建子进程 |
| execve | 59 | 执行程序 |
11.2 使用系统调用读取文件
.section .text .globl _start _start: ; open("test.txt", O_RDONLY) mov $2, %rax lea filename(%rip), %rdi xor %rsi, %rsi syscall ; read(fd, buffer, 128) mov %rax, %rdi ; fd = 返回值 mov $0, %rax lea buffer(%rip), %rsi mov $128, %rdx syscall ; write(1, buffer, bytes_read) mov %rax, %rdx mov $1, %rax mov $1, %rdi lea buffer(%rip), %rsi syscall ; exit mov $60, %rax xor %rdi, %rdi syscall .section .data filename: .asciz "test.txt" .section .bss buffer: .space 128第十二部分:调试技巧
12.1 使用GDB调试
gcc-g-oprog main.c add.s gdb ./prog(gdb)breakadd(gdb)run(gdb)info registers(gdb)p$rax(gdb)set$rax=42(gdb)disassemble(gdb)stepi(gdb)continue常用GDB命令:
| 命令 | 描述 |
|---|---|
info registers | 显示所有寄存器 |
info registers rax | 显示RAX |
p $rax | 打印RAX值 |
set $rax = 42 | 设置RAX=42 |
x/10x $rsp | 以16进制显示栈上10个字 |
x/s $rdi | 显示字符串 |
disassemble | 反汇编当前函数 |
disassemble main | 反汇编main函数 |
stepi | 单步执行一条指令 |
nexti | 单步执行(跳过子调用) |
break *0x401000 | 在地址设断点 |
watch *0x1000 | 监视内存地址 |
12.2 查看汇编输出
gcc-S-O2main.c# 生成汇编代码objdump-dmain# 反汇编可执行文件objdump-d-Mintel main# Intel语法反汇编gdb-batch-ex"disassemble main"./prog第十三部分:常用伪指令与汇编器指令
13.1 数据定义(GAS)
| 指令 | 描述 | 示例 |
|---|---|---|
.byte | 定义8位数据 | .byte 0x01, 0x02 |
.short | 定义16位数据 | .short 0x1234 |
.word | 定义32位数据 | .word 0x12345678 |
.long | 定义32位数据 | .long 0x12345678 |
.quad | 定义64位数据 | .quad 0x1234567890ABCDEF |
.ascii | 定义字符串 | .ascii "Hello" |
.asciz | 定义字符串(自动添加NULL) | .asciz "Hello" |
.space | 预留空间 | .space 100 |
.rept | 重复定义 | .rept 4; .byte 0; .endr |
13.2 分段指令
| 指令 | 描述 |
|---|---|
.text | 代码段 |
.data | 初始化数据段 |
.rodata | 只读数据段 |
.bss | 未初始化数据段 |
.section .note.GNU-stack | 声明栈不需要可执行权限 |
13.3 其他常用指令
| 指令 | 描述 |
|---|---|
.globl symbol | 导出符号(全局可见) |
.hidden symbol | 导出为隐藏符号 |
.align n | 按n字节对齐 |
.p2align n | 按2^n字节对齐 |
.size symbol, size | 设置符号大小 |
.type symbol, @function | 设置符号类型为函数 |
第十四部分:性能优化技巧
- 减少内存访问:尽量使用寄存器,将频繁访问的变量保存在寄存器中
- 指令并行:避免指令间数据依赖,提升流水线效率
- 使用SIMD:批量处理数据,单指令多数据提升吞吐量
- 分支预测优化:将常见路径放在前面,减少分支误预测
- 缓存对齐:数据按64字节(缓存行大小)对齐避免伪共享
- 减少函数调用开销:内联小函数或使用
__attribute__((always_inline)) - 使用LEA进行简单算术:比ADD+MUL组合更快
- 编译器优化:使用
-O2或-O3让编译器自动优化
附录A:x86-64指令速查表
| 类别 | 指令示例 | 功能 |
|---|---|---|
| 传送 | MOV, LEA, XCHG | 数据传送、地址计算 |
| 算术 | ADD, SUB, MUL, DIV | 加、减、乘、 |
