3.2 寄存器

x86-64 架构提供了 16 个通用寄存器,每个 64 位宽。寄存器是 CPU 内部最快的存储层次,在指令执行中扮演核心角色。

16 个通用寄存器

64位32位16位8位用途
%rax%eax%ax%al返回值
%rbx%ebx%bx%bl被调用者保存
%rcx%ecx%cx%cl第 4 个参数
%rdx%edx%dx%dl第 3 个参数
%rsi%esi%si%sil第 2 个参数
%rdi%edi%di%dil第 1 个参数
%rbp%ebp%bp%bpl基址指针(被调用者保存)
%rsp%esp%sp%spl栈指针(特殊管理)
%r8%r8d%r8w%r8b第 5 个参数
%r9%r9d%r9w%r9b第 6 个参数
%r10%r10d%r10w%r10b调用者保存
%r11%r11d%r11w%r11b调用者保存
%r12%r12d%r12w%r12b被调用者保存
%r13%r13d%r13w%r13b被调用者保存
%r14%r14d%r14w%r14b被调用者保存
%r15%r15d%r15w%r15b被调用者保存

寄存器的子集访问

x86-64 兼容早期 x86 架构,允许通过不同名称访问同一个寄存器的低字节部分:

# 以下操作都影响 %rax,但操作宽度不同
movq    $0x123456789ABCDEF0, %rax   # 写入全部 64 位
movl    $0xFFFFFFFF, %eax            # 写入低 32 位,高 32 位清零!
movw    $0xFFFF, %ax                 # 写入低 16 位,不影响高位
movb    $0xFF, %al                   # 写入低 8 位,不影响高位

重要movl 写入 32 位寄存器时,会自动将高 32 位清零(%eax%rax 高 32 位置零)。这是 x86-64 的约定行为。

寄存器的核心用途

函数参数传递

前 6 个整数/指针参数按顺序通过寄存器传递:

  • 第一个参数 → %rdi
  • 第二个参数 → %rsi
  • 第三个参数 → %rdx
  • 第四个参数 → %rcx
  • 第五个参数 → %r8
  • 第六个参数 → %r9

栈管理

  • %rsp:始终指向当前栈帧的栈顶,由 push/pop/call/ret 指令隐式修改
  • %rbp:可选作为栈帧基址指针,用于访问局部变量和参数

函数返回值

  • %rax:保存函数返回值
  • %rdx:在某些返回 128 位结果的场景中与 %rax 配合使用

寄存器保存约定

详见 :

  • 调用者保存(caller-saved):%rax, %rcx, %rdx, %rsi, %rdi, %r8~%r11
    • 调用者若需在函数调用后保留其值,必须在 call 之前自行保存
  • 被调用者保存(callee-saved):%rbx, %rbp, %r12~%r15
    • 被调函数若使用这些寄存器,必须在返回 之前 恢复原始值

寄存器 vs 内存

特性寄存器内存
访问延迟~0.5-1 ns~50-100 ns (主存)
容量16 × 8 = 128 字节GB 级别
地址无地址(通过名称访问)有地址(指针访问)

编译器会尽可能将频繁使用的变量分配到寄存器中,称为寄存器分配(register allocation)。

相关笔记

    • 寄存器作为操作数的用法
    • 参数在寄存器中的传递规则
    • 寄存器保存约定详解
    • %rsp 与栈的关系

链接到