Skip to content

Latest commit

 

History

History
270 lines (224 loc) · 13.8 KB

CSAPP-3-汇编.md

File metadata and controls

270 lines (224 loc) · 13.8 KB

CH3 汇编基础

3.1 通用寄存器

x86-64共16个通用寄存器,都是64bit的,遵循的规则:

生成1字节和2字节数字的指令会保持其余的字节内容不变
生成4字节数字的指令会把高4字节置0.

(1) 通用寄存器名称

名称 作用 备注
%rax 返回值
%rbx 被调用者保存
%rcx 第4个参数
%rdx 第3个参数
%rsi 第2个参数
%rdi 第1个参数
%rbp 被调用者保存
%rsp 栈指针 用于指明运行时栈的结束位置
%r8 第5个参数
%r9 第6个参数
%r10 调用者保存
%r11 调用者保存
%r12 被调用者保存
%r13 被调用者保存
%r14 被调用者保存
%r15 被调用者保存

(2) 标志寄存器

标志位 名称 值为 1 时
CF 进位标志 发生进位
PF 奇偶标志 偶数
AF 辅助进位标志 发生进位
ZF 零标志 比较结果相等
SF 符号标志 负数
OF 溢出标志 发生溢出

(3) 寻址方式

类型 格式 操作数值 寻址方式 示例
立即数 $Imm Imm 立即数寻址 $0x108
立即数0x108
寄存器 ra R[ra] 寄存器寻址 %rax
寄存器rax中的值
存储器 Imm M[Imm] 绝对寻址 0x104
addr=0x104
addr中的值
存储器 (ra) M[R[ra]] 间接寻址 (%rax)
addr=寄存器rax中的值
addr中的值
存储器 Imm(rb) M[Imm+R[rb]] (基址+偏移)寻址 4(%rax)
addr=寄存器rax中的值+4
addr中的值
存储器 (rb, ri) M[R[rb]+R[ri]] 变址寻址 (%rax, %rdx)
addr=寄存器rax中的值+寄存器rdx中的值
addr中的值
存储器 Imm(rb, ri) M[Imm+R[rb]+R[ri]] 变址寻址 9(%rax, %rdx)
addr=寄存器rax中的值+寄存器rdx中的值+9
addr中的值
存储器 (,ri, s) M[R[ri]+s] 比例变址寻址 (, %rdx, 8)
addr=寄存器rdx中的值*8
addr中的值
存储器 Imm(,ri, s) M[Imm+R[ri]+s] 比例变址寻址 0xFC(, %rdx, 8)
addr=寄存器rdx中的值*8+0xFC
addr中的值
存储器 (rb, ri, s) M[R[rb] + R[ri]*s] 比例变址寻址 (%rax, %rdx, 4)
addr=寄存器rax中的值+寄存器rdx中的值*4
addr中的值
存储器 Imm(rb, ri, s) M[Imm+R[rb]+R[ri]*s] 比例变址寻址 0xFC(%rax, %rdx, 4)
addr=寄存器rax中的值+寄存器rdx中的值*4+0xFC
addr中的值

比例因子s必须为1,2,4,8;

(4) x86-64指令位宽

C语言 指令 位宽(bit) 示例 其它
int8 b 8 movb
int16 w 16 movw
int32 l 32 movl 4字节的指令,会把寄存器高4字节清0
int64 q 64 movq
long q 64
char* q 64
float ss 32 vomvss
double sd 64 vmovsd

(5) 指令

指令 类型 含义
MOV S, D 传送 目的为内存地址或寄存器
movb
movw
movl 传送32bit
movq
movabsq I, R 传送绝对的64bit到寄存器R
MOVZ S, R 零扩展传送 目的为寄存器,以0扩展
movzbw
movzbl (会把高4字节也清零)
movzbq
movzwl
movzwq
MOVS S, R 符号扩展传送 传送符号扩展的到寄存器
movsbw
movsbl
movsbq
movswl
movswq
movslq
cltq 将%eax符号扩展到%rax
pushq S 入栈出栈 subq $8, %rsp; movq %rax, (%rsp)
popq D movq (%rsp), %rax; addq $8, %rsp
leaq S, D 运算 加载有效地址(常用于指针), leaq (%rdx, %rdi, 4), %rax;
即%rax=%rax+%rdi*4
INC D D += 1, incq 16(%rax)
DEC D D -= 1
NEG D D = -D
NOT D D = ~D
ADD S, D
SUB S, D
XOR S, D D ^= S
OR S, D D
AND S, D D &= S
SAL k, D D <<= k(逻辑左移)
SHL k, D D <<= k(算术左移)
SAR k, D D >>= k
SHR k, D D >>= k(符号位填充)
imulq S 乘除 (64bit乘法,单操作数)结果为 S*%rax; 高位存放于rdx, 低位存放在rax
mulq S
mul S, D (双操作数)D *= S; 结果存放在D中
imul S, D (双操作数)D *= S (无符号)
clto 对rax的符号位进行扩展,扩展的结果存放在rdx中
cqto 对rax的符号位进行扩展. 扩展的符号位放在rdx中
idivq S (64bit除法) 结果为 %rax除以S; 商存放在rax, 余数存放在rdx
divq S
div S, D
idiv S, D
cmp S1, S2 比较 用S2 - S1的结果来设置标志寄存器ZF(S1=S2,ZF=1; else ZF=0)
test S1, S2 用S1 & S2的结果来设置标志寄存器ZF
sete D D=ZF (结果相等, ZF=1)
setne D D=~ZF
sets D D=SF (负数,SF=1)
setns D D=~SF
setg D 有符号>
setge D 有符号>=
setl D 有符号<
setle D 有符号<=
seta D 无符号>
setae D 无符号>=
setb D 无符号<
setbe D 无符号<=
jmp Label 跳转
jmp *Opera
je Label ZF=0 跳转
jne Label
js Label SF=1 负数跳转
jns Label
jg Label 有符号>
jge Label
jl Label
jle Label
ja Label 无符号>
jae Label
jb Label
jbe Label
cmove S, R 条件传送 根据前一条语句(cmp, test)结果,决定本语句. 相等(ZF=1), 把S的值赋给R
cmovne S, R 不相等
cmovs S, R 负数
cmovns S, R 非负数
cmovg S, R 有符号>; g/ge/l/le
cmova S, R 无符号>; a/ae/b/be

switch语句,GCC根据case的数量、case值的稀疏程度来翻译switch...case...语句. 当case的数量多于4个且值的跨度范围较小时,使用跳转表.

(6) 函数调用与恢复

栈往下增长。上为大地址,下为小地址。 函数调用过程: 多余参数入栈(若参数个数>6); 返回地址入栈;

在代码中,经常可用看到 movq 16(%rsp), %rax,表明把第二个参数赋给rax
(%rsp),函数返回地址
8(%rsp),入栈的第一个参数(假设参数为8字节类型)
16(%rsp),入栈的第二个参数

有些寄存器是被调用者可以修改的,有些是被调用者不能修改的。被调用者要想使用这些寄存器,需要先把这些寄存器的值入栈,最后再出栈恢复。

3.2 浮点数寄存器

SSE指令要求数据块16bit对齐,即SSE单元和内存之间传输数据的指令要求内存地址必须是16的整数倍。
x86-64处理器实现了AVX多媒体指令(SSE指令的超集),支持AVX的指令并没有强制性的对齐要求。
代码优化建议,64bit系统8字节对齐、32bit系统4字节对齐。

(1) SIMD指令寄存器长度变化表

指令名称 寄存器名称 寄存器长度 寄存器个数 编译命令
MMX mm 64 bit
SSE xmm 128 bit
AVX ymm 256 bit 16(ymm0-ymm15) -mavx2, 生成AVX2代码
AVX寄存器名称 长度(bit) 作用及要求
ymm0 256 1st FP arg返回值
ymm1 - ymm7 256 2nd FP参数 - 8th FP参数
ymm8 - ymm15 256 调用者保存

ymm0-ymm7,可以用来依次传递8个浮点数参数,也可以用栈传递额外的参数
使用ymm0传递返回值
所有的ymm都是调用者保存

可以把xmm寄存器(128bit)看成一个数组,4个32bit数组[x32,x32,x32,x32]或2个64bit数组[x64,x64]。

AVX(Advanced vector extension, 高级向量扩展)是SIMD的最新版本,每个寄存器256bit,可以一次执行8个四字节或4个八子节的计算。

假设%ymm0包含8个float数据(a0, ..., a8), %rcx包含8个float数据的内存地址。vmulps (%rcx), %ymm0, %ymm1, 一次从内存中读取8个值,并行的执行8个乘法。 然后把计算的结果保存在%ymm1中。

(2) 指令缩写对照表

缩写 含义
ss 单精度浮点数
sd 双精度浮点数
si 整数(默认32bit)
q 64bit
cvt convert

(3) 浮点数传送指令表

指令 目的 描述 寄存器和内存
vmovss M32 X 传送单精度 M32: 32bit内存
vmovss X M32 传送单精度 X: 寄存器xmm
vmovsd M64 X 传送双精度 M64: 64bit内存
vmovsd X M64 传送双精度
vmovaps X X 传送对齐的封装好的单精度 a:aligned,16bit对齐
vmovapd X X 传送对其的封装好的双精度

(4) 浮点数转换成整数指令表

指令 目的 描述 速查
vcvttss2si X/M32 R32 用截断的方法把单精度数转成整数 32(float) -> 32(int)
vcvttsd2si X/M64 R32 用截断的方法把双精度数转成整数 64(double) -> 32(int)
vcvttss2siq X/M32 R64 用截断的方法把单精度数转成64bit整数 32(float) -> 64(int64)
vcvttsd2siq X/M64 R64 用截断的方法把双精度数转成64bit整数 64(double) -> 64(int64)

R32: 32bit通用寄存器
M32: 32bit内存

整数转换成浮点指令表

指令 源1 源2 目的 描述 速查
vcvtsi2ss M32/R32 X X 把32bit整数转成单精度 32(int32) -> 32(float)
vcvtsi2sd M32/R32 X X 把32bit整数转成双精度 32(int32) -> 64(double)
vcvtsi2ssq M64/R64 X X 把64bit整数转成单精度 64(int64/long) -> 32(float)
vcvtsi2sdq M64/R64 X X 把64bit整数转成双精度 64(int64/long) -> 64(double)

(5) 浮点数运算指令表

指令(单精度) 指令(双精度) 效果 描述
vaddss vaddsd D <- S2 + S1 加法
vsubss vsubsd D <- S2 - S1 减法
vmulss vmulsd D <- S2 * S1 乘法
vdivss vdivsd D <- S2 / S1 除法
vmaxss vmaxsd D <- max(S2, S1) 求最大值
vminss vminsd D <- min(S2, S1) 求最小值
sqrtss sqrtsd D <- 开方(S1) 浮点数平方根

vdivsd %xmm1, %xmm2, %xmm2,含义为xmm2 = xmm2 / xmm1;

(6) 浮点数其它指令

指令(单精度) 指令(双精度) 效果 描述
vxorps vxorpd D <- S2 ^ S1 按位异或
vandps vandpd D <- S2 & S1 按位与
ucomiss ucomisd CF/ZF/PF 比较指令,根据S2-S1结果设置标志位