汇编语言 - 教程
汇编语言教程
汇编语言是面向处理器的低级编程语言,使用助记符代替机器指令,与硬件一一对应,是理解计算机底层原理的最佳途径。
本教程包含
- 基础篇:简介、环境搭建、基础语法、内存分段、寄存器
- 指令篇:系统调用、寻址方式、算术/逻辑指令、条件判断、循环
- 进阶篇:数字/字符串处理、数组、过程、递归、宏、文件与内存管理
学习价值
- 深入理解 CPU 如何执行指令
- 掌握内存布局与指针本质
- 为逆向工程、内核开发打基础
- 写出极致高效的底层代码
环境说明
本教程以 x86 汇编(Intel 语法)和 NASM 汇编器为例,在 Linux/macOS 上演示,Windows 用户可用 MASM 对应学习。
汇编语言 - 简介
汇编语言简介
汇编语言(Assembly Language)是机器指令的符号化表示,每条汇编指令基本对应一条机器指令。
语言层级
高级语言(Java/Python/C)
↓ 编译
汇编语言(mov/add/sub)
↓ 汇编器
机器语言(0101...)
为什么学习汇编
- 理解底层:寄存器、栈、内存寻址的运作方式
- 调试能力:看懂反汇编,定位疑难 Bug
- 性能极致:关键代码可手工优化
- 安全研究:逆向、漏洞分析的基础
汇编与机器指令对应
机器码: B8 01 00 00 00
汇编: mov eax, 1 ; 把 1 放入 eax 寄存器
主流汇编风格
- Intel 语法:目标在前,如
mov eax, 1(NASM/MASM) - AT&T 语法:源在前,如
movl $1, %eax(GAS)
本教程采用 Intel 语法与 NASM 汇编器。
汇编语言 - 环境搭建
汇编语言环境搭建
搭建汇编开发环境需要:汇编器(NASM)、链接器(ld)和调试器(可选)。
安装 NASM
# Ubuntu/Debian
sudo apt install nasm
# macOS
brew install nasm
# Windows
下载 nasm.exe 并加入 PATH
验证安装
nasm -v
# NASM version 2.15.05
编译运行流程
# 1. 编写 hello.asm
# 2. 汇编成目标文件
nasm -f elf64 hello.asm -o hello.o
# 3. 链接生成可执行文件
ld hello.o -o hello
# 4. 运行
./hello
调试工具(推荐)
# GDB 支持汇编级调试
gdb ./hello
(gdb) break _start
(gdb) run
(gdb) info registers
(gdb) x/10i $eip
32 位环境使用 nasm -f elf 与 ld -m elf_i386,需安装 32 位库。
汇编语言 - 基础语法
汇编语言基础语法
汇编程序由指令、标签、伪指令和注释组成。
程序基本结构
section .data ; 数据段:存放已初始化数据
msg db "Hello", 0
section .bss ; BSS 段:未初始化数据
buffer resb 64
section .text ; 代码段
global _start ; 入口点(链接器可见)
_start:
; 指令
mov eax, 1 ; 系统调用号(exit)
mov ebx, 0 ; 返回值
int 0x80 ; 触发系统调用
语法要素
- 指令:操作码 + 操作数,如
mov eax, 1 - 标签:
_start:冒号结尾,表示地址 - 伪指令:db/dw/dd/resb 等,告诉汇编器分配数据
- 注释:分号
;之后为注释 - 常量:立即数(数字)、字符('A')
数据定义伪指令
db 定义字节(8位)
dw 定义字(16位)
dd 定义双字(32位)
dq 定义四字(64位)
resb 预留字节
resw 预留字汇编语言 - 内存分段
汇编语言内存分段
x86 架构使用分段模型组织内存,程序分为多个段。
三个基本段
数据段(.data) 存放已初始化全局变量
BSS 段(.bss) 存放未初始化变量(不占文件空间)
代码段(.text) 存放机器指令
堆栈段(stack) 存放局部变量和调用信息(由系统管理)
为什么分段
- 不同段有不同的访问权限(代码段只读)
- 便于链接器重定位
- 现代操作系统使用分页+分段管理内存
段寄存器
CS 代码段寄存器
DS 数据段寄存器
SS 堆栈段寄存器
ES 附加段寄存器
FS/GS 通用附加段
64 位模式的变化
x86-64 中段寄存器的作用弱化(平坦内存模型),但分段概念仍是理解 ELF 文件布局的关键。
查看 ELF 段
readelf -S hello.o # 查看节(section)
objdump -h hello.o汇编语言 - 寄存器
汇编语言寄存器
寄存器是 CPU 内部的高速存储单元,是所有指令操作的直接对象。
x86-64 通用寄存器
64位 低32位 低16位 低8位 用途
rax eax ax al 累加器(返回值)
rbx ebx bx bl 基址
rcx ecx cx cl 计数
rdx edx dx dl 数据
rsi esi si sil 源索引
rdi edi di dil 目标索引
rbp ebp bp bpl 基址指针(栈帧)
rsp esp sp spl 栈指针
r8-r15 部分可访问低32/16/8位
专用寄存器
rip 指令指针(下一条指令地址)
rflags 标志寄存器(ZF零标志、SF符号、CF进位、OF溢出)
使用示例
mov rax, 10 ; rax = 10
mov rbx, 20
add rax, rbx ; rax = 30
sub rax, 5 ; rax = 25
调用约定
System V 约定:函数参数依次放入 rdi、rsi、rdx、rcx、r8、r9,返回值放 rax。
汇编语言 - 系统调用
汇编语言系统调用
系统调用是用户程序请求操作系统服务的接口,在汇编中通过中断指令触发。
32 位系统调用(int 0x80)
; 系统调用号放入 eax
; 参数依次放入 ebx, ecx, edx, esi, edi
; 执行 int 0x80
; 示例:退出程序(exit, 调用号 1)
mov eax, 1 ; sys_exit
mov ebx, 0 ; 退出码
int 0x80
64 位系统调用(syscall)
; 系统调用号放入 rax
; 参数依次放入 rdi, rsi, rdx, r10, r8, r9
; 执行 syscall
; 示例:write 输出
mov rax, 1 ; sys_write
mov rdi, 1 ; fd = 1 (stdout)
mov rsi, msg ; 缓冲区地址
mov rdx, len ; 长度
syscall
常用系统调用号
sys_read 0 读取
sys_write 1 写入
sys_open 2 打开文件
sys_close 3 关闭文件
sys_exit 60(64位)/1(32位) 退出
完整示例:输出 Hello
section .data
msg db "Hello, World!", 10, 0
len equ $ - msg
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, len
syscall
mov rax, 60
xor rdi, rdi
syscall汇编语言 - 寻址方式
汇编语言寻址方式
寻址方式决定指令如何计算操作数的地址,是汇编的核心概念。
六种基本寻址方式
; 1. 立即寻址:操作数就是常量
mov eax, 42
; 2. 寄存器寻址:操作数是寄存器
mov eax, ebx
; 3. 直接寻址:操作数是内存地址
mov eax, [0x1000]
mov eax, [var] ; var 的地址
; 4. 寄存器间接寻址:寄存器存放地址
mov eax, [ebx]
; 5. 变址寻址:基址+变址
mov eax, [ebx + ecx]
; 6. 基址变址+偏移
mov eax, [ebx + ecx*4 + 8]
寻址示例解析
arr 是数组基地址,访问第 i 个 int 元素:
mov eax, [arr + i*4]
LEA 指令(取地址)
lea eax, [arr + ecx*4] ; 把计算结果地址放入 eax,不访问内存
注意
- 方括号
[]表示访问内存 - 64 位模式寄存器寻址需用 r 前缀
- 立即数在 Intel 语法中不需要前缀
汇编语言 - 变量
汇编语言变量
汇编中的"变量"本质是内存单元的符号化地址,通过伪指令定义。
定义变量
section .data
age db 25 ; 字节变量,初值 25
price dw 1000 ; 字变量
total dd 100000 ; 双字变量
pi dq 3.14 ; 四字浮点
name db "Alice", 0 ; 字符串
arr db 1, 2, 3, 4 ; 字节数组
BSS 段定义未初始化变量
section .bss
buffer resb 256 ; 预留 256 字节
count resd 1 ; 预留 1 个双字
访问变量
mov eax, [age] ; 读取
mov [age], eax ; 写入
mov byte [age], 30 ; 写入时需指定大小
EQU 定义常量
section .data
msg db "Hello"
len equ $ - msg ; 常量 = 当前位置 - 起始地址 = 字符串长度
大小修饰符
byte [addr] 8位
word [addr] 16位
dword [addr] 32位
qword [addr] 64位汇编语言 - 常量
汇编语言常量
常量在汇编中用 EQU 或 %define 定义,在汇编阶段就替换为具体值,不占用内存。
EQU 常量
; EQU 定义后不能修改
MAX_SIZE equ 100
BUFFER equ 0x1000
mov eax, MAX_SIZE ; 等价 mov eax, 100
数值表示
mov eax, 100 ; 十进制
mov eax, 0x64 ; 十六进制(0x 前缀)
mov eax, 0b1100100 ; 二进制(0b 前缀)
mov eax, 144q ; 八进制(q 后缀)
mov eax, 'A' ; 字符常量 = 65
表达式常量
SECTION .data
len1 equ 10
len2 equ 20
total equ len1 + len2 ; 30,汇编时计算
宏定义(%define)
%define SIZE 10
%define SUM(a,b) (a+b)
mov eax, SIZE ; 展开为 mov eax, 10
mov ebx, SUM(3,4) ; 展开为 mov ebx, (3+4)
常量 vs 变量
- 常量:汇编期替换,不占内存,只读
- 变量:运行期存在内存中,可读写
汇编语言 - 算术指令
汇编语言算术指令
算术指令对寄存器或内存中的数值进行运算。
基本算术指令
add dest, src 加法:dest += src
sub dest, src 减法:dest -= src
mul src 无符号乘法:eax * src → edx:eax
imul dest, src 有符号乘法
div src 无符号除法:edx:eax / src
idiv src 有符号除法
inc dest 自增:dest++
dec dest 自减:dest--
neg dest 取负:dest = -dest
示例
mov eax, 10
mov ebx, 3
add eax, ebx ; eax = 13
sub eax, 5 ; eax = 8
inc eax ; eax = 9
dec eax ; eax = 8
neg eax ; eax = -8
乘法细节
; mul:32位下 eax * src,结果 64 位存入 edx:eax
mov eax, 200000
mov ebx, 3
mul ebx ; eax = 600000, edx = 0
除法细节
; div:被除数在 edx:eax(64位),商→eax,余数→edx
mov eax, 100
xor edx, edx ; 高32位清零
mov ecx, 7
div ecx ; eax = 14(商), edx = 2(余数)
注意
除零会触发异常;除法前必须正确初始化 edx(有符号用 cdq 扩展符号位)。
汇编语言 - 逻辑指令
汇编语言逻辑指令
逻辑指令对二进制位进行操作,常用于位运算和掩码。
逻辑运算指令
and dest, src 按位与
or dest, src 按位或
xor dest, src 按位异或
not dest 按位取反
shl dest, n 逻辑左移
shr dest, n 逻辑右移
sal dest, n 算术左移(同 shl)
sar dest, n 算术右移(保留符号位)
rol dest, n 循环左移
ror dest, n 循环右移
示例
mov eax, 0b1100
mov ebx, 0b1010
and eax, ebx ; eax = 0b1000
or eax, ebx ; eax = 0b1010
xor eax, eax ; eax = 0 (清零常用技巧)
not eax ; 全 1
; 位移
mov eax, 5 ; 0b0101
shl eax, 1 ; 0b1010 = 10 (左移1位=×2)
shr eax, 1 ; 5 (右移1位=÷2)
常见用途
xor eax, eax:高效清零- 掩码提取位:
and eax, 0xFF取低 8 位 - 乘除 2 的幂用移位替代
- 标志位操作
TEST 指令
test eax, eax ; 与运算但不保存结果,只影响标志
; 常用于判断是否为 0:jz 跳转汇编语言 - 条件判断
汇编语言条件判断
条件判断依赖标志寄存器和条件跳转指令,CMP 指令用于比较。
CMP 指令
cmp a, b ; 计算 a - b,只更新标志,不保存结果
; ZF=1 表示相等;CF=1 表示 a < b(无符号);SF/OF 表示有符号大小
条件跳转指令
je 相等跳转 jne 不相等跳转
jg 大于(有符号) jge 大于等于
jl 小于(有符号) jle 小于等于
ja 大于(无符号) jae 大于等于
jb 小于(无符号) jbe 小于等于
jz 为零 jnz 非零
jmp 无条件跳转
if-else 结构
; 伪代码: if (eax > ebx) goto bigger;
cmp eax, ebx
jle not_bigger ; eax <= ebx 则跳过
; bigger 分支
mov ecx, 1
jmp done
not_bigger:
; else 分支
mov ecx, 0
done:
比较示例
mov eax, 10
cmp eax, 5
jg greater ; 10 > 5,跳转
; ...
greater:
; 执行
注意
有符号比较用 jg/jl/jge/jle,无符号比较用 ja/jb/jae/jbe,混淆会导致错误。
汇编语言 - 循环结构
汇编语言循环结构
汇编中循环通过跳转指令实现,常用 LOOP 指令或计数器+条件跳转。
LOOP 指令
; LOOP 使用 ecx 作为计数器,每次执行 ecx--,非零则跳转
mov ecx, 5
loop_start:
; 循环体
dec eax
loop loop_start ; ecx--, 若 ecx!=0 跳回
通用循环模式(while)
; 打印 1..10 的伪代码循环
mov eax, 1 ; i = 1
loop_begin:
cmp eax, 10
jg loop_end ; if (i > 10) break
; 循环体:处理 eax
inc eax ; i++
jmp loop_begin
loop_end:
do-while 模式
loop_body:
; 循环体(至少执行一次)
dec ecx
jnz loop_body ; ecx != 0 继续
数组求和示例
section .data
arr db 1, 2, 3, 4, 5
n equ 5
section .text
mov ecx, n ; 计数器
xor eax, eax ; sum = 0
mov esi, 0 ; 索引
sum_loop:
add al, [arr + esi]
inc esi
loop sum_loop汇编语言 - 数字处理
汇编语言数字处理
数字在汇编中有整数和浮点两类处理方式,还涉及 ASCII 与数值的转换。
整数表示
无符号: 0 ~ 2^n - 1
有符号: 补码表示,最高位为符号位
8位: -128 ~ 127
16位: -32768 ~ 32767
32位: -2^31 ~ 2^31-1
ASCII 数字转数值
; 字符 '5' = 53,减 48 得数值 5
mov al, '5'
sub al, 48 ; al = 5
数值转 ASCII
mov al, 7
add al, 48 ; al = '7'
多位数字转字符串
; 12345 → "12345"(循环除以10取余)
mov eax, 12345
mov ecx, 10
mov edi, buffer_end ; 从后往前写
conv_loop:
xor edx, edx
div ecx ; eax = 商, edx = 余数(0-9)
add dl, '0'
dec edi
mov [edi], dl
test eax, eax
jnz conv_loop
浮点处理
; SSE 指令处理单精度/双精度浮点
movss xmm0, [float_val] ; 加载
addss xmm0, xmm1 ; 相加
cvtsi2ss xmm0, eax ; int 转 float汇编语言 - 字符串处理
汇编语言字符串处理
x86 提供专门的字符串指令,配合 REP 前缀可高效处理字符串。
常用字符串指令
movsb/movsw/movsd 按字节/字/双字拷贝
lodsb/lodsw/lodsd 从源加载到 AL/AX/EAX
stosb/stosw/stosd 存储到目标
cmpsb/cmpsw/cmpsd 比较
scasb/scasw/scasd 扫描
rep 重复(配合 ecx 计数)
repe/repne 条件重复
字符串拷贝示例
section .data
src db "Hello", 0
section .bss
dst resb 16
; 拷贝 6 字节(含结束符)
cld ; 方向标志清零(向前)
mov esi, src
mov edi, dst
mov ecx, 6
rep movsb ; 重复拷贝 ecx 次
计算字符串长度
; 用 scasb 找结尾的 0
cld
mov edi, src
mov ecx, -1 ; 最大计数
xor al, al ; 找 0
repne scasb
; ecx 的补码关系可得长度
汇编中字符串定义
msg1 db "Hello", 0 ; C 风格(结尾0)
msg2 db 'A', 'B', 'C' ; 逐字符
msg3 db 0x48, 0x65 ; 十六进制字节
msg4 times 10 db 0 ; 10 个 0汇编语言 - 数组
汇编语言数组
汇编中数组是连续内存,通过基址+偏移寻址访问元素。
定义数组
section .data
bytes_arr db 10, 20, 30 ; 字节数组
words_arr dw 100, 200, 300 ; 字数组
dword_arr dd 1000, 2000, 3000 ; 双字数组
str_arr db "Hello", 0
访问数组元素
; 字节数组(元素大小 1)
mov al, [bytes_arr + 1] ; 第 1 个元素 = 20
; 双字数组(元素大小 4)
mov eax, [dword_arr + 2*4] ; 第 2 个元素 = 3000
; 用索引寄存器
mov ecx, 0 ; index
mov eax, [dword_arr + ecx*4] ; 第 0 个元素
遍历数组求和
mov ecx, 3 ; 元素个数
xor eax, eax ; sum = 0
xor esi, esi ; index = 0
loop_sum:
add eax, [dword_arr + esi*4]
inc esi
loop loop_sum
数组大小计算
; $ - arr 得到数组总字节数
arr_len equ ($ - dword_arr) / 4 ; 元素个数
二维数组
; 3行4列 int 数组, 行主序
; 元素 [i][j] 的地址 = base + (i*4 + j) * 4
mov eax, [matrix + (i*4 + j)*4]汇编语言 - 过程(子程序)
汇编语言过程(子程序)
过程(CALL/RET)用于代码复用,是汇编中的"函数"。
定义与调用
; 调用
call my_func
; 定义
my_func:
; 过程体
ret ; 返回
栈与调用过程
call 指令:
1. 把返回地址(下一条指令)压栈
2. 跳转到过程地址
ret 指令:
1. 弹出返回地址
2. 跳回调用点
带参数的过程(寄存器传参)
; 求和过程: a + b = c
add_numbers:
mov eax, [esp+4] ; 第一个参数
mov ebx, [esp+8] ; 第二个参数
add eax, ebx
ret
; 调用
push 10
push 20
call add_numbers
add esp, 8 ; 清理参数(栈平衡)
栈帧(标准写法)
my_func:
push rbp ; 保存旧栈帧
mov rbp, rsp ; 建立新栈帧
sub rsp, 16 ; 分配局部变量空间
; ... 过程体 ...
mov rsp, rbp ; 恢复栈
pop rbp
ret
注意
- 嵌套调用时栈自动管理返回地址
- 过程内使用寄存器前要先保存(push)再恢复(pop)
- 递归深度过大可能栈溢出
汇编语言 - 递归
汇编语言递归
递归过程调用自身,依赖栈保存每层状态。
阶乘示例(n!)
; 递归阶乘:factorial(n) = n * factorial(n-1)
factorial:
push rbp
mov rbp, rsp
mov eax, [rbp+16] ; n
cmp eax, 1
jle base_case ; n <= 1 时返回 1
; n > 1: n * factorial(n-1)
push eax ; 保存 n
dec eax
push eax
call factorial ; 递归调用
add esp, 4
pop ebx ; 恢复 n
imul eax, ebx ; eax = n * factorial(n-1)
jmp done
base_case:
mov eax, 1
done:
mov rsp, rbp
pop rbp
ret
; 调用: factorial(5)
push 5
call factorial
add esp, 4
; eax = 120
递归执行过程
factorial(5)
→ 5 * factorial(4)
→ 5 * 4 * factorial(3)
→ 5 * 4 * 3 * factorial(2)
→ 5 * 4 * 3 * 2 * factorial(1)
→ 5 * 4 * 3 * 2 * 1 = 120
注意
- 必须有终止条件(基准情况)
- 每层调用都会压栈,深度有限
- 64 位模式参数传递可用寄存器(rdi),减少栈操作
汇编语言 - 宏
汇编语言宏
宏(NASM 中 %macro)是汇编阶段的文本替换,用于代码复用和可读性。
简单宏定义
%macro print_msg 2
; 输出字符串宏: %1 = 消息地址, %2 = 长度
mov rax, 1
mov rdi, 1
mov rsi, %1
mov rdx, %2
syscall
%endmacro
使用宏
section .data
hello db "Hello", 10
hellolen equ $ - hello
section .text
print_msg hello, hellolen
宏与过程对比
| 特性 | 宏 | 过程 |
|---|---|---|
| 展开时机 | 汇编期 | 运行期 |
| 代码体积 | 每处调用都复制 | 只有一份 |
| 性能 | 无调用开销 | 有 call/ret 开销 |
| 适用 | 短小高频代码 | 大型复杂逻辑 |
多行宏与局部标签
%macro swap 2
%%tmp equ 0
mov eax, %1
mov ebx, %2
mov [%%tmp], eax ; %% 前缀为宏内局部标签
mov %1, ebx
mov %2, [%%tmp]
%endmacro
条件汇编
%ifdef DEBUG
; 调试代码
%else
; 发布代码
%endif汇编语言 - 文件管理
汇编语言文件管理
汇编中通过系统调用打开、读取、写入、关闭文件。
文件系统调用(32位)
sys_open 5 打开
sys_close 6 关闭
sys_read 3 读取
sys_write 4 写入
sys_lseek 19 定位
打开文件示例
; int open("file.txt", O_RDONLY, 0)
mov eax, 5 ; sys_open
mov ebx, filename ; 文件名字符串地址
mov ecx, 0 ; O_RDONLY
mov edx, 0 ; 权限
int 0x80 ; eax = 文件描述符
读取文件
mov eax, 3 ; sys_read
mov ebx, fd ; 文件描述符
mov ecx, buffer ; 缓冲区
mov edx, 256 ; 最大读取字节
int 0x80 ; eax = 实际读取字节数
写入与关闭
; 写入
mov eax, 4 ; sys_write
mov ebx, fd
mov ecx, data
mov edx, len
int 0x80
; 关闭
mov eax, 6 ; sys_close
mov ebx, fd
int 0x80
完整流程
open → read/write → close
错误处理
系统调用返回负值表示错误(如 -2 文件不存在),可用 errno 判断,或检查返回值符号。
汇编语言 - 内存管理
汇编语言内存管理
汇编程序通过系统调用 brk/mmap 申请内存,或使用静态分配的段。
静态内存分配
section .bss
buffer resb 1024 ; 静态分配 1KB,编译期确定
动态内存申请(brk)
; sys_brk(32位): 设置程序堆末尾
; 用法: 先取当前堆顶,再增加大小
mov eax, 45 ; sys_brk
xor ebx, ebx ; 参数 0,返回当前堆顶
int 0x80
; eax = 当前堆顶地址
; 申请 1024 字节
add eax, 1024
mov ebx, eax
mov eax, 45
int 0x80
; eax = 新堆顶(即分配的内存起始)
mmap 分配(64位)
; sys_mmap, 申请匿名内存
mov rax, 9 ; sys_mmap
xor rdi, rdi ; addr = NULL(内核选择)
mov rsi, 4096 ; length
mov rdx, 3 ; prot = PROT_READ|PROT_WRITE
mov r10, 0x22 ; flags = MAP_PRIVATE|MAP_ANONYMOUS
mov r8, -1 ; fd = -1
xor r9, r9 ; offset
syscall
; rax = 分配的内存地址
栈上分配
sub rsp, 1024 ; 栈上临时分配 1KB
; 使用 [rsp] 开始的区域
add rsp, 1024 ; 释放
注意
- 动态分配的内存使用后要释放(munmap/调整 brk)
- 栈分配超出栈大小会崩溃
- 现代编程建议直接调用 malloc/free(C 库)
汇编指令速查表
汇编指令速查表
常用 x86 指令快速参考,按类别整理。
数据传送
mov dest, src 传送
push src 压栈
pop dest 出栈
lea dest, [addr] 取有效地址
xchg a, b 交换
movzx dest, src 零扩展传送
movsx dest, src 符号扩展传送
算术运算
add / sub / mul / imul
div / idiv / inc / dec / neg
adc(带进位加) / sbb(带借位减)
cmp(比较,影响标志)
逻辑与移位
and / or / xor / not
shl / shr / sal / sar
rol / ror / rcl / rcr
test(与运算,仅标志)
跳转
jmp / je / jne / jz / jnz
jg / jge / jl / jle (有符号)
ja / jae / jb / jbe (无符号)
jc / jnc(进位) / jo / jno(溢出)
loop / loopne
过程与字符串
call / ret / enter / leave
movsb / movsw / movsd
lodsb / stosb / cmpsb / scasb
rep / repe / repne
cld / std(方向标志)
标志操作
clc(清进位) / stc(置进位) / cmc(取反)
pushf / popf(压/弹标志)
其他
nop(空操作) / int(中断) / syscall
hlt(停机) / cpuid(识别CPU)汇编语言 - 学习资源
汇编语言学习资源
推荐的学习资源和工具,帮助你继续深入汇编与底层开发。
经典书籍
- 《汇编语言(第4版)》王爽:中文入门经典,配套 DOS 环境练习
- 《x86 汇编语言:从实模式到保护模式》:深入硬件底层
- 《Computer Systems: A Programmer's Perspective》(CSAPP):系统视角理解汇编
- 《Professional Assembly Language》:英文进阶
在线资源
- NASM 官方文档:nasm.us
- Felix Cloutier 的 x86 指令参考(felixcloutier.com)
- Godbolt Compiler Explorer:高级语言转汇编对照
- GNU 汇编器文档:GAS 手册
练习平台
- 逆向工程练习:crackmes.one
- CTF 平台:pwn.college、picoCTF
- 编程竞赛汇编题:CS:APP labs
调试工具
gdb 汇编级调试
objdump 反汇编
readelf 查看 ELF 结构
strace 跟踪系统调用
radare2 逆向工具
学习路线建议
- 用 NASM 写 20 个小程序(打印、计算、排序)
- 用 gdb 单步调试,观察寄存器变化
- 用 objdump 反汇编 C 程序,对照源码理解
- 尝试阅读和修改简单恶意软件样本(安全环境)
汇编语言 - 总结
汇编语言总结
恭喜你完成汇编语言教程!以下是核心知识点回顾。
核心知识回顾
- 程序结构:.data / .bss / .text 三段 + _start 入口
- 寄存器:rax-eax-ax-al 层级、rflags 标志寄存器
- 寻址:立即、寄存器、直接、间接、变址六种方式
- 指令集:mov/add/sub/mul/div、逻辑与移位、cmp 与条件跳转
- 流程控制:if-else、while、LOOP 计数器循环
- 数据:变量、常量、数组、字符串指令(rep movsb)
- 结构化编程:过程(call/ret)、递归、宏(%macro)
- 系统交互:int 0x80 / syscall、文件读写、内存管理
汇编能力进阶
- 读反汇编:用 objdump/gdb 分析任意二进制
- 优化:理解编译器生成的指令,手工微调热点
- 逆向:从二进制还原逻辑,理解保护与对抗
- 内核/驱动:汇编是内核开发的底层语言
关键提醒
- 有符号/无符号比较指令(jg vs ja)不要混用
- 除法前正确初始化高 32 位(edx)
- 过程调用注意栈平衡(push/pop 配对)
- 64 位模式用 syscall,32 位用 int 0x80
汇编学习是"慢即是快",动手写代码、单步调试观察寄存器,才是掌握底层原理的不二法门。