
寄存器 vs 内存
| 寄存器 | 内存 | |
|---|---|---|
| 位置 | CPU 内 | CPU 外 |
| 访问速度 | 快 | 慢 |
| 容量 | 小 | 大 |
| 成本 | 高 | 低 |
| 表示方式 | 名字 | 地址 |
| 地址 | 无 | 多种寻址方式 |
存储层次结构

汇编语言的操作类型
- 对寄存器数据或内存数据进行算数和逻辑操作
- 内存与寄存器间、寄存器与寄存器间传递数据
- 程序执行顺序的转移
数据格式
| 类型 | 汇编代码后缀 | 大小(字节) |
|---|---|---|
| 字节 | b | 1 |
| 字 | w | 2 |
| 双字 | l | 4 |
| 四字 | q | 8 |
访问信息
一个 x 86-64 的 CPU 包含一组 16 个通用目的寄存器。 当指令以寄存器作为目标时:
- 生成 1 或 2 字节数字的指令会保持剩下的字节不变
- 生成 4 字节数字的指令会把高位 4 字节置为 0
特别地,%rsp 用于指示运行时栈的结束位置。
操作数指示符
操作数分为三个类型:
- 立即数:用
$Imm表示,比如$42、$0x1F- 不同的指令允许的立即数范围不同
- 寄存器
- 以下用 表示任意寄存器,用 表示它的值
- 内存引用
- 以下用 表示
寻址模式
| 类型 | 格式 | 数值 |
|---|---|---|
| 立即数 | \I mm$ | |
| 寄存器 | ||
| 内存 | ,其中可以省略任意项, 必须是 1、2、4、8 其中之一 |
数据传送指令
MOV S, D
包括 movb, movw, movl, movq
特别地,movabsq I, R 表示传送绝对的四字,movq 只能以表示为 32 位补码的立即数作为源操作数,movabsq 可以以任意 64 位立即数作为源操作数。
MOVZ & MOVS
MOVZ 会将目的中剩余字节填充为 0,MOVS 会根据源操作的最高位将剩余字节填充 0 或 1。movzbw, movzbl, …
其中不存在 movzlq,原因是效果和 movl 完全相同。
另外,有指令 cltq,总是将 %eax 符号扩展到 %rax,效果和 movslq %eax, %rax 完全一致。
压入或弹出栈数据
pushq
pushq S,将四字压入栈,%rsp -= 8
popq
popq D,将四字弹出栈,%rsp += 8
算数和逻辑操作
以下各指令类都有不同大小操作数的变种(leaq 除外)。
加载有效地址
leaq,相当于取源操作数的地址写入到目的。
它可以用于表示简单的算术操作。比如 leaq 7(%rdx, %rdx, 4), %rax 表示将 %rax 的值设置为 。
- ! 目的操作数必须是一个寄存器。
一元操作与二元操作
| 一元操作 | 描述 |
|---|---|
| INC | 加 1 |
| DEC | 减 1 |
| NEG | 取负 |
| NOT | 取反 |
| 二元操作 |
|---|
| ADD |
| SUB |
| IMUL |
| XOR |
| OR |
| AND |
| 结果总是存储在目的操作数中。 |
移位操作
先给出位移量,再给出要移位的数。
- ! 移位量只允许是一个立即数或存放在
%cl中,实际移位量由低 m 位决定,其中 , 是目的操作数的位长。 - 右移指令:SAR 表示算数右移,SHR 表示逻辑右移
控制
条件码
- CF:最高位进位标志,用于检测无符号溢出
- ZF:零标志
- SF:符号标志,最近的操作结果为负数
- OF:溢出标志,最近的操作导致了补码溢出(正溢出&负溢出,
t=a+b,检测是否 a, b 符号相同,而 t 符号不同) - 条件码由算术指令隐含设置,leaq 不设置条件码
CMP
CMP S1, S2
计算 ,设置条件码,但不改变目的寄存器数值。
TEST
TEST S1, S2
计算 ,设置条件码,但不改变目的寄存器数值。
访问条件码
根据条件码设置字节为 0 或 1
SETX 指令,一般在 CMP 指令后使用,后缀表示不同的条件,目的操作数必须是单字节寄存器或内存。
- ! 有符号数和无符号数的
set指令不同! - 有符号<:
setl,^ - 无符号<:
setb, - 其余可以通过逻辑简单推出
跳转
JX 指令,一般在 CMP 指令后使用,后缀表示不同的条件,语法为 。 跳转目标有多种编码方式,比如用目标指令地址与紧跟在跳转指令后的那条指令的地址的差表示或用绝对地址表示。
通过条件跳转实现条件分支
C 语言中的 if-else 语句:
if (test-expr)
then-statement
else
else-statement汇编通常采用以下形式:
t = test-expr;
if (!t)
goto false;
then-statement
goto done;
false:
else-statement
done:通过条件传送来实现条件分支
能更好利用现代处理器的流水线。 CMOVX 指令,源和目的的值可以是 16 位、32 位或 64 位,根据条件码判断是否进行数据传送。 如果两个表达式中任意一个可能产生副作用,就会导致非法行为。
循环
do-while循环
do {
body-statement
} while (test-expr)loop:
body-statement
t = test-expr
if (t)
goto loopwhile 循环
while (test-expr)
body-statementgoto test;
loop:
body-statement
test:
t = test-expr
if (t)
goto loop;for 循环
for (init-expr; test-expr; update-expr)
body-statementinit-expr;
goto test;
loop:
body-statement
update-expr;
test:
t = test-expr;
if (t)
goto loop;switch 语句
使用跳转表实现。
jmp *.L4(,%rdi,8) 间接跳转,表的基地址为 .L4,每一表项占据 8 字节。
过程
运行时栈
- 从高地址向低地址增长
- 由
%rsp存储栈顶地址
转移控制
call指令:将下一条指令的地址 A 压入栈中,将 PC 设置为函数的起始地址ret指令:从栈中弹出返回地址 A,并将 PC 设置为 A
数据传送
- ~ 参数少于 7 个时,从左到右依次用 rdi、rsi、rdx、rcx、r8、r9 传递参数
- 参数大于等于 7 个时,从右向左压入栈中,数据大小向 8 的倍数对齐