寄存器(Registers)
通用寄存器(64 / 32 / 16 / 8 位)
x86-64 提供 16 个 64 位通用寄存器,向下兼容访问低 32/16/8 位:
| 64 位 | 32 位 | 16 位 | 8 位(低) | 8 位(高) | 传统用途 |
|---|---|---|---|---|---|
%rax |
%eax |
%ax |
%al |
%ah |
累加器 / 返回值 |
%rbx |
%ebx |
%bx |
%bl |
%bh |
基址(被调用者保存) |
%rcx |
%ecx |
%cx |
%cl |
%ch |
计数器 / 第 4 参数 |
%rdx |
%edx |
%dx |
%dl |
%dh |
数据 / 第 3 参数 |
%rsi |
%esi |
%si |
%sil |
— | 源指针 / 第 2 参数 |
%rdi |
%edi |
%di |
%dil |
— | 目的指针 / 第 1 参数 |
%rsp |
%esp |
%sp |
%spl |
— | 栈指针 |
%rbp |
%ebp |
%bp |
%bpl |
— | 帧指针 |
%r8–%r15 |
%r8d–%r15d |
%r8w–%r15w |
%r8b–%r15b |
— | 第 5–6 参数及临时 |
注意事项:
- 高 8 位名字
%ah/%bh/%ch/%dh只有a/b/c/d四个寄存器才有;%r8–%r15没有高 8 位名字。且一旦指令用到 REX 前缀(涉及%r8–%r15、%sil/%dil等),%ah等不可用,此时要用%al类名字。 %spl/%bpl/%sil/%dil也是 x86-64 新增的 8 位名字。
子寄存器写操作的关键规则(务必记住)
- 写 32 位子寄存器会把整个 64 位寄存器的高 32 位清零。因此
movl $0, %eax即把%rax整体清零,比movq $0, %rax更短,是惯用清零写法;同理movl %ecx, %eax本身就是 32→64 的零扩展。 - 写 8/16 位子寄存器(
%al、%ax)不影响高位。要保留高位地取%al等,正常使用即可;但要小心依赖旧的%rax高位时别被低 8 位写入破坏。
参数传递约定(x86-64 System V ABI)
函数前 6 个整数参数依次放入:%rdi, %rsi, %rdx, %rcx, %r8, %r9;
返回值放入 %rax。超出 6 个的参数通过栈传递。详见模块六。
专用寄存器
%rip:指令指针(程序计数器)。不能当作普通操作数使用,但可出现在leaq label(%rip), %rax这类 RIP 相对寻址中(PIC 代码常用,见模块十二)。32 位模式对应%eip(不支持直接读取,通常经call/pop技巧获得)。- 标志寄存器
%eflags/%rflags:保存状态位(ZF、CF、SF、OF 等),被条件跳转指令读取。位含义见模块四。 - 段寄存器:
%cs %ds %ss %es %fs %gs(用户态通常无需显式使用,%fs常用于线程局部存储)。 - 控制/调试寄存器:
%cr0..%cr4、%dr0..%dr7(内核态使用)。
浮点与向量寄存器(详见模块十)
- x87 栈式寄存器:
%st(0)–%st(7),80 位。 - SSE 寄存器:
%xmm0–%xmm15,128 位。 - AVX 寄存器:
%ymm0–%ymm15(256 位,为 XMM 的扩展);AVX-512 有 512 位%zmm0–%zmm31及掩码寄存器%k0–%k7。 - 浮点参数经
%xmm0–%xmm7传递,浮点返回值在%xmm0。
寄存器保存约定
| 类别 | 寄存器 | 含义 |
|---|---|---|
| 调用者保存(caller-saved) | %rax %rcx %rdx %rsi %rdi %r8 %r9 %r10 %r11 |
调用函数前需自行保存 |
| 被调用者保存(callee-saved) | %rbx %rbp %r12 %r13 %r14 %r15 %rsp |
被调用函数须保证其值不变 |
# 交换两个寄存器内容
xchg %rax, %rbx