汇编语言 - 教程

汇编语言教程

汇编语言是面向处理器的低级编程语言,使用助记符代替机器指令,与硬件一一对应,是理解计算机底层原理的最佳途径。

本教程包含

  • 基础篇:简介、环境搭建、基础语法、内存分段、寄存器
  • 指令篇:系统调用、寻址方式、算术/逻辑指令、条件判断、循环
  • 进阶篇:数字/字符串处理、数组、过程、递归、宏、文件与内存管理

学习价值

  • 深入理解 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    逆向工具

学习路线建议

  1. 用 NASM 写 20 个小程序(打印、计算、排序)
  2. 用 gdb 单步调试,观察寄存器变化
  3. 用 objdump 反汇编 C 程序,对照源码理解
  4. 尝试阅读和修改简单恶意软件样本(安全环境)

汇编语言 - 总结

汇编语言总结

恭喜你完成汇编语言教程!以下是核心知识点回顾。

核心知识回顾

  • 程序结构:.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、文件读写、内存管理

汇编能力进阶

  1. 读反汇编:用 objdump/gdb 分析任意二进制
  2. 优化:理解编译器生成的指令,手工微调热点
  3. 逆向:从二进制还原逻辑,理解保护与对抗
  4. 内核/驱动:汇编是内核开发的底层语言

关键提醒

  • 有符号/无符号比较指令(jg vs ja)不要混用
  • 除法前正确初始化高 32 位(edx)
  • 过程调用注意栈平衡(push/pop 配对)
  • 64 位模式用 syscall,32 位用 int 0x80

汇编学习是"慢即是快",动手写代码、单步调试观察寄存器,才是掌握底层原理的不二法门。

第 1 / 25 节