运算、分支与循环 笔记
用大白话 + C 语言类比来理解汇编。每节先讲"这东西干嘛的",再给能直接抄的模板。
一、算术运算
1.1 加法和减法
最基本的,就像 C 里 a += b 和 a -= b:
add ax, bx ; ax = ax + bx
sub ax, bx ; ax = ax - bx自增自减(对应 C 的 i++ / i--):
inc ax ; ax++
dec ax ; ax--取反(把正数变负数、负数变正数):
neg ax ; ax = -ax (比如 ax=3 → ax=-3)比较两个数(用于后面的分支跳转):
cmp ax, bx ; 计算 ax - bx,但不保存结果,只改变标志位
; 后面紧跟 jxx 指令来判断大小关系1.2 乘法
乘法分无符号 mul 和有符号 imul,结果会放到固定的寄存器里:
; --- 8位 × 8位 → 16位结果 ---
mov al, 5
mov bl, 3
mul bl ; ax = al × bl = 15
; --- 16位 × 16位 → 32位结果(存在 dx:ax 里)---
mov ax, 100
mov bx, 200
mul bx ; dx:ax = ax × bx = 20000
; dx 放高16位,ax 放低16位简单记:8位乘法看 al,结果在 ax;16位乘法看 ax,结果在 dx:ax。
1.3 除法
除法分无符号 div 和有符号 idiv,商和余数分别存在不同寄存器:
; --- 16位 ÷ 8位 ---
mov ax, 17 ; 被除数放 ax
mov bl, 5 ; 除数放 bl
div bl ; al = 17/5 = 3(商),ah = 17%5 = 2(余数)
; --- 32位 ÷ 16位 ---
mov ax, 17 ; 被除数放 dx:ax
mov dx, 0 ; ← 别忘了清零 dx!(无符号除法)
mov bx, 5
div bx ; ax = 商,dx = 余数做有符号除法时,要用扩展指令把符号位填到高位:
mov ax, -10 ; 被除数
cwd ; ★ 把 ax 符号扩展到 dx:ax(dx 全填符号位)
mov bx, 3
idiv bx ; ax = -3(商),dx = -1(余数)扩展指令口诀:
cbw= byte→word(al → ax)cwd= word→dword(ax → dx:ax)cdq= dword→qword(eax → edx:eax)
二、逻辑运算与移位
2.1 逻辑运算
和 C 语言的位运算一模一样:
and ax, bx ; ax = ax & bx (按位与,常用来"清零"某些位)
or ax, bx ; ax = ax | bx (按位或,常用来"置1"某些位)
xor ax, bx ; ax = ax ^ bx (按位异或)
not ax ; ax = ~ax (按位取反)两个常用技巧:
xor ax, ax ; 快速把 ax 清零(比 mov ax, 0 更快)
test ax, 1 ; 检查 ax 最低位是不是 1(奇偶判断),配合 jnz/jz
test就像and,但只影响标志位、不修改操作数。
2.2 移位
移位 = 把所有二进制位往左或右挪:
shl ax, 1 ; 逻辑左移1位 → ax = ax × 2
shl ax, 3 ; 左移3位 → ax = ax × 8 (需要 .386)
shr ax, 1 ; 逻辑右移1位 → ax = ax / 2 (无符号,高位补0)
sar ax, 1 ; 算术右移1位 → ax = ax / 2 (有符号,高位补符号位)简单记:左移 = 乘2,右移 = 除2。
shl/shr给无符号数用,sar给有符号数用。
移位次数要么写常数,要么放cl里:shl ax, cl。
三、分支(if-else 怎么写)
汇编没有 if,要用 cmp + 条件跳转 来实现。
3.1 核心思路
cmp a, b ← 比较
jxx label ← 根据比较结果,决定跳不跳3.2 跳转指令选哪个?
对照 C 语言来记最简单:
无符号数(把数当正数看)—— 用 above / below:
| C 语言写法 | 汇编跳转 | 助记 |
|---|---|---|
a > b | ja | jump if above |
a >= b | jae | above or equal |
a < b | jb | jump if below |
a <= b | jbe | below or equal |
有符号数(有正有负)—— 用 greater / less:
| C 语言写法 | 汇编跳转 | 助记 |
|---|---|---|
a > b | jg | jump if greater |
a >= b | jge | greater or equal |
a < b | jl | jump if less |
a <= b | jle | less or equal |
等于/不等于(通用):
| C 语言写法 | 汇编跳转 | 助记 |
|---|---|---|
a == b | je | jump if equal |
a != b | jne | not equal |
其他:
jz(结果为零)、jnz(结果非零)、jc(有进位)、jnc(无进位)、jo(溢出)、jno(无溢出)
3.3 可以直接套的模板
if-else:
; ---- C 语言:if (ax > bx) { A } else { B } ----
cmp ax, bx
jle else_part ; 如果 ax <= bx,跳去 else(注意:条件取反!)
; ---- A: then 部分 ----
jmp end_if ; 跳过 else
else_part:
; ---- B: else 部分 ----
end_if:关键技巧:
jxx里的条件要写成"不满足时跳走",也就是把 C 的条件取反。例如 C 里
if (ax > bx)→ 汇编里写jle else(不大于就跳走)。
if 不带 else(更简单):
; ---- C 语言:if (ax == 0) { A } ----
cmp ax, 0
jne skip ; ax != 0 就跳过
; ---- A ----
skip:多分支(switch-case 风格):
; ---- C 语言:if (ax==1) {A} else if (ax==2) {B} else {C} ----
cmp ax, 1
je do_A
cmp ax, 2
je do_B
jmp do_C ; 都不是,走默认
do_A:
; ---- A ----
jmp done
do_B:
; ---- B ----
jmp done
do_C:
; ---- C ----
done:求较大值 max(ax, bx) → ax:
cmp ax, bx
jge done ; ax 已经 >= bx,不用动
mov ax, bx ; 否则把 bx 给 ax
done:四、循环(for / while 怎么写)
4.1 loop 指令(最常用)
loop = 把 cx 减 1,如果 cx 不为 0 就跳回去。对应 C 的 for (int i = N; i > 0; i--)。
; ---- 循环 N 次 ----
mov cx, N ; cx = 循环次数
again:
; ---- 循环体(随便写)----
loop again ; cx--,cx≠0 就跳回 again实战:计算 1+2+...+100:
xor ax, ax ; ax = 0,用来累加
mov cx, 100 ; 循环 100 次
sum:
add ax, cx ; ax += cx(cx 从 100 递减到 1)
loop sum
; 结束后 ax = 5050⚠️ 小心:
loop是先 cx-- 再判断,所以如果进入循环前 cx=0,会循环 65536 次!
4.2 while 循环
没有专门指令,用 cmp + jxx + jmp 自己搭:
; ---- C 语言:while (ax != 0) { ax-- } ----
while_start:
cmp ax, 0
je while_end ; ax == 0 → 退出循环
dec ax ; ax--(循环体)
jmp while_start ; 跳回开头继续判断
while_end:4.3 do-while 循环
循环体至少执行一次,判断放在最后:
; ---- C 语言:do { ax-- } while (ax != 0) ----
do_start:
dec ax ; 循环体
cmp ax, 0
jne do_start ; ax != 0 → 继续循环4.4 嵌套循环
loop 只认 cx,所以嵌套时要用栈保存外层的 cx:
; ---- 外层 5 次 × 内层 10 次 ----
mov cx, 5
outer:
push cx ; ★ 保存外层 cx
mov cx, 10
inner:
; ---- 内层循环体 ----
loop inner
pop cx ; ★ 恢复外层 cx
loop outer五、标志位(看不懂跳转条件时来查这里)
CPU 每做一次运算,都会自动设置这些标志位,jxx 就是根据它们来决定跳不跳的:
| 标志 | 全称 | 什么时候 = 1 | 一句话理解 |
|---|---|---|---|
| ZF | Zero | 运算结果 = 0 | "结果是零吗?" |
| CF | Carry | 无符号运算溢出 / 借位 | "进位了吗?" |
| SF | Sign | 结果最高位 = 1 | "结果是负数吗?"(有符号时看这个) |
| OF | Overflow | 有符号运算溢出 | "有符号溢出了吗?" |
不常用的:PF(结果低 8 位中 1 的个数为偶数)、AF(低 4 位向高 4 位进位,BCD 用)、DF(字符串方向)。