寄存器(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