x86-64汇编从入门到精通

发布时间:2026/8/3 5:07:35
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环境推荐编译器GCCgcc或Clang汇编器GASGNU Assembleras或NASM调试器GDB反汇编工具objdumpmacOS环境编译器ClangXcode自带汇编器ASGNU assembler随Xcode安装调试器LLDBWindows环境可使用MinGW、Cygwin或WSL2推荐MASM微软宏汇编器或NASM验证环境gcc--versionas--versiongdb--version第三部分x86-64编程模型3.1 寄存器一览x86-64的寄存器体系需要重点掌握通用寄存器64位64位32位16位8位低用途RAXEAXAXAL累加器返回值RBXEBXBXBL被调用者保存RCXECXCXCL计数器第4个参数RDXEDXDXDL第3个参数RSIESISISIL第2个参数RDIEDIDIDIL第1个参数RBPEBPBPBPL帧指针被调用者保存RSPESPSPSPL栈指针R8-R15R8D-R15DR8W-R15WR8B-R15B扩展寄存器特殊寄存器寄存器用途RIP指令指针程序计数器RFLAGS状态标志寄存器XMM0-XMM15128位SIMD寄存器浮点/向量YMM0-YMM15256位SIMD寄存器AVXZMM0-ZMM15512位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个参数RCXLinux/ R10macOS第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-64AArch64寄存器数量16个通用寄存器31个通用寄存器指令编码变长1-15字节固定32位栈增长方向向下地址减小向下地址减小参数传递RDI, RSI, RDX, RCX, R8, R9X0-X7返回值RAXX0帧指针RBP可选X29固定分支指令JMP, JccB, B.cond第四部分x86-64指令集入门4.1 指令格式概览x86指令采用变长编码典型格式为[opcode] [dest], [src1], [src2]示例ATT语法movq %rax, %rbx ; RBX RAX addq $10, %rax ; RAX 10示例Intel语法mov rbx, rax ; RBX RAX add rax, 10 ; RAX 10两种语法对比ATT语法Intel语法源操作数在前目标在后目标在前源在后寄存器前加%寄存器不加%立即数前加$立即数不加$内存地址用()内存地址用[]movl $1, (%rax)mov dword [rax], 1本文主要使用Intel语法更直观。4.2 寻址模式模式示例有效地址立即数mov rax, 42直接使用42寄存器mov rax, rbxRBX的值直接内存mov rax, [0x1000]地址0x1000的内存寄存器间接mov rax, [rbx]RBX指向的内存基址偏移mov rax, [rbx16]RBX16基址索引mov rax, [rbxrcx*8]RBXRCX*8基址索引偏移mov rax, [rbxrcx*48]RBXRCX*48RIP相对mov rax, [ripoffset]RIPoffset4.3 数据宽度后缀x86指令需要指明操作数宽度后缀宽度示例b8位字节movb al, blw16位字movw ax, bxl32位双字movl eax, ebxq64位四字movq rax, rbx第五部分常用指令大全5.1 数据传送指令指令描述示例MOV传送数据mov rax, rbxMOVZX零扩展传送movzx rax, byte [rsi]MOVSX符号扩展传送movsx rax, byte [rsi]MOVSXD符号扩展32位到64位movsxd rax, eaxLEA加载有效地址lea rax, [rbxrcx*4]XCHG交换数据xchg rax, rbxPUSH压栈push raxPOP出栈pop raxPUSHF压入标志寄存器pushfPOPF弹出标志寄存器popfLEA的妙用不访问内存只计算地址常用于快速算术运算lea rax, [rcxrcx*4] ; RAX RCX * 5 lea rax, [raxrax*2] ; RAX RAX * 35.2 算术运算指令指令描述示例ADD加法add rax, rbxADC带进位加法adc rax, rbxSUB减法sub rax, rbxSBB带借位减法sbb rax, rbxINC自增1inc raxDEC自减1dec raxIMUL有符号乘法imul rax, rbxMUL无符号乘法mul rbxIDIV有符号除法idiv rbxDIV无符号除法div rbxNEG取负neg raxCMP比较cmp rax, rbx注意MUL和DIV使用RAX和RDXMUL rbxRDX:RAX RAX * RBXDIV rbxRAX RDX:RAX / RBXRDX 余数5.3 逻辑运算指令指令描述示例AND按位与and rax, rbxOR按位或or rax, rbxXOR按位异或xor rax, raxNOT按位取反not raxTEST测试与AND同不写结果test rax, raxSHL逻辑左移shl rax, 2SHR逻辑右移shr rax, 2SAR算术右移符号扩展sar rax, 2ROL循环左移rol rax, 1ROR循环右移ror rax, 15.4 分支与跳转指令指令描述示例JMP无条件跳转jmp labelCALL调用函数call funcRET从函数返回retJE/JZ相等/零跳转je labelJNE/JNZ不相等/非零跳转jne labelJG/JNLE有符号大于跳转jg labelJGE/JNL有符号大于等于跳转jge labelJL/JNGE有符号小于跳转jl labelJLE/JNG有符号小于等于跳转jle labelJA/JNBE无符号大于跳转ja labelJAE/JNB无符号大于等于跳转jae labelJB/JNAE无符号小于跳转jb labelJBE/JNA无符号小于等于跳转jbe label条件跳转的反向了解对立条件便于代码优化条件对立条件JE (相等)JNE (不相等)JG (有符号大于)JLE (有符号小于等于)JL (有符号小于)JGE (有符号大于等于)JA (无符号大于)JBE (无符号小于等于)JB (无符号小于)JAE (无符号大于等于)5.5 标志寄存器与条件码RFLAGS寄存器中的关键标志位标志含义设置条件ZF零标志结果为零运算结果等于0SF符号标志结果为负最高位为1CF进位标志无符号溢出运算产生进位/借位OF溢出标志有符号溢出符号位错误PF奇偶标志低8位含偶数个1偶数个15.6 位操作与条件传送指令指令描述示例BSWAP字节序反转bswap raxBT位测试bt rax, 3BTS位测试并置1bts rax, 3BTR位测试并清零btr rax, 3BTC位测试并取反btc rax, 3CMOVcc条件传送cmovg rax, rbxSETcc条件设置setg alCMOV示例cmp rax, rbx cmovl rax, rbx ; if (rax rbx) rax rbx取最大值5.7 栈操作指令指令描述等效操作PUSH reg压栈sub rsp, 8; mov [rsp], regPOP reg出栈mov reg, [rsp]; add rsp, 8PUSHQ imm压入立即数sub rsp, 8; mov [rsp], immENTER创建栈帧少用LEAVE销毁栈帧mov rsp, rbp; pop rbp第六部分第一个汇编程序6.1 Hello WorldLinux文件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.sLinux/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#includestdio.hexternintadd(inta,intb);intmain(){intresultadd(3,5);printf(Result: %d\\n,result);return0;}编译与运行gcc-cadd.s-oadd.o gcc-oprog main.c add.o ./prog第七部分栈帧管理7.1 函数入口与出口模式标准函数序言Prologuefunc_name: push rbp ; 保存旧的帧指针 mov rbp, rsp ; 设置新的帧指针 sub rsp, frame_size ; 分配局部变量空间标准函数尾声Epiloguemov 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扩展扩展寄存器宽度数据类型SSEXMM0-XMM15128位单精度浮点4个SSE2XMM0-XMM15128位双精度浮点2个AVXYMM0-YMM15256位8个单精度/4个双精度AVX-512ZMM0-ZMM15512位16个单精度/8个双精度8.2 浮点运算指令指令描述示例MOVSS加载/存储单精度movss xmm0, [mem]MOVSD加载/存储双精度movsd xmm0, [mem]ADDSS单精度加法addss xmm0, xmm1ADDSD双精度加法addsd xmm0, xmm1SUBSS单精度减法subss xmm0, xmm1SUBSD双精度减法subsd xmm0, xmm1MULSS单精度乘法mulss xmm0, xmm1MULSD双精度乘法mulsd xmm0, xmm1DIVSS单精度除法divss xmm0, xmm1DIVSD双精度除法divsd xmm0, xmm1SQRTSS单精度平方根sqrtss xmm0, xmm1SQRTSD双精度平方根sqrtsd xmm0, xmm1CVTSI2SS整数转单精度浮点cvtsi2ss xmm0, eaxCVTSS2SI单精度浮点转整数cvtss2si eax, xmm0CVTSI2SD整数转双精度浮点cvtsi2sd xmm0, eaxCVTSD2SI双精度浮点转整数cvtsd2si eax, xmm0UCOMISS比较单精度ucomiss xmm0, xmm1UCOMISD比较双精度ucomisd xmm0, xmm18.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(ab){resulta;}else{resultb;}对应汇编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代码intsum0;for(inti0;i100;i){sumi;}对应汇编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(n0){resultn;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 targetmov rcx, 100 loop_start: ; 循环体 loop loop_start注意LOOP在现代CPU上性能通常不如显式的DECJNZ不推荐在性能敏感代码中使用。第十部分实战示例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, [rdircx*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, [rdirdx*4] ; arr[i] mov ebx, [rdirdx*44] ; arr[i1] cmp eax, ebx jle no_swap mov [rdirdx*4], ebx ; 交换 mov [rdirdx*44], 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, [rdirax*4] mulss xmm1, [rsirax*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, [rdirax*4] mulps xmm1, [rsirax*4] addps xmm0, xmm1 add rax, 4 loop loop4 ; 水平相加 haddps xmm0, xmm0 haddps xmm0, xmm0 ; 处理剩余元素 remainder: ; ... 处理余数 ret第十一部分系统调用Linux11.1 Linux系统调用速查表x86-64系统调用使用syscall指令参数通过寄存器传递参数寄存器系统调用号RAX第1个参数RDI第2个参数RSI第3个参数RDX第4个参数R10第5个参数R8第6个参数R9返回值RAX常用系统调用调用名RAX值说明read0读取文件write1写入文件open2打开文件close3关闭文件stat4获取文件状态fstat5获取文件状态文件描述符mmap9内存映射mprotect10修改内存保护brk12调整数据段大小socket41创建socketconnect42连接socketsendto44发送数据recvfrom45接收数据exit60退出进程getpid39获取进程IDfork57创建子进程execve59执行程序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$rax42(gdb)disassemble(gdb)stepi(gdb)continue常用GDB命令命令描述info registers显示所有寄存器info registers rax显示RAXp $rax打印RAX值set $rax 42设置RAX42x/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-exdisassemble 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; .endr13.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进行简单算术比ADDMUL组合更快编译器优化使用-O2或-O3让编译器自动优化附录Ax86-64指令速查表类别指令示例功能传送MOV, LEA, XCHG数据传送、地址计算算术ADD, SUB, MUL, DIV加、减、乘、