跳到主要内容

寄存器模型

寄存器是 CPU 内部最快速的存储单元,理解寄存器模型是学习 x86 汇编的基础。本章将详细介绍 x86 架构的各种寄存器。

寄存器概述

x86 架构的寄存器经历了从 16 位到 32 位再到 64 位的演变。现代 x86-64 处理器提供了丰富的寄存器资源。

寄存器分类

x86 寄存器主要分为以下几类:

  • 通用寄存器:用于算术运算、逻辑运算和数据传送
  • 段寄存器:用于内存分段管理
  • 标志寄存器:存储处理器状态和运算结果标志
  • 指令指针:指向下一条要执行的指令
  • 控制寄存器:控制处理器行为(特权级操作)
  • 调试寄存器:用于调试功能

通用寄存器

64 位通用寄存器

x86-64 架构提供了 16 个 64 位通用寄存器:

64 位寄存器32 位16 位8 位低8 位高主要用途
RAXEAXAXALAH累加器、返回值
RBXEBXBXBLBH基址寄存器
RCXECXCXCLCH计数器、循环计数
RDXEDXDXDLDH数据寄存器、I/O
RSIESISISIL-源变址寄存器
RDIEDIDIDIL-目标变址寄存器
RBPEBPBPBPL-栈帧基址指针
RSPESPSPSPL-栈指针
R8R8DR8WR8B-通用寄存器
R9R9DR9WR9B-通用寄存器
R10R10DR10WR10B-通用寄存器
R11R11DR11WR11B-通用寄存器
R12R12DR12WR12B-通用寄存器
R13R13DR13WR13B-通用寄存器
R14R14DR14WR14B-通用寄存器
R15R15DR15WR15B-通用寄存器

寄存器继承关系

x86 架构保持了向后兼容性,64 位寄存器的低 32 位、16 位和 8 位部分可以独立访问:

┌─────────────────────────────────────┐
│ RAX (64位) │
├─────────────────────┬───────────────┤
│ │ EAX (32位) │
├─────────────────────┼───────┬───────┤
│ │ AX │ │
│ │(16位) │ │
│ ├───┬───┤ │
│ │AH │AL │ │
│ │8位│8位│ │
└─────────────────────┴───┴───┴───────┘

访问低 32 位寄存器会自动将高 32 位清零:

mov rax, 0x123456789ABCDEF0
mov eax, 0 ; RAX = 0x0000000000000000(高32位被清零)

mov rax, 0x123456789ABCDEF0
mov ax, 0 ; RAX = 0x123456789ABC0000(仅低16位被修改)

传统寄存器的特殊用途

虽然现代 x86-64 中大多数寄存器都是通用的,但某些寄存器仍有特殊用途:

RAX/EAX - 累加器

  • 算术运算的默认寄存器
  • 函数返回值存放位置
  • 乘除法的隐含操作数
mul rbx        ; RAX = RAX * RBX(128位结果在 RDX:RAX)
div rbx ; RAX = RAX / RBX,RDX = 余数

RCX/ECX - 计数器

  • 循环指令的计数器
  • 字符串操作重复前缀的计数器
mov rcx, 10
loop_label:
; 循环体
loop loop_label ; RCX--,如果 RCX != 0 则跳转

RSI/ESI 和 RDI/EDI - 变址寄存器

  • 字符串操作的源和目标指针
  • 数组访问的常用寄存器
; 字符串复制
mov rsi, source ; 源地址
mov rdi, dest ; 目标地址
mov rcx, length ; 长度
rep movsb ; 重复复制字节

RSP/ESP - 栈指针

  • 指向当前栈顶
  • 自动被 push、pop、call、ret 等指令修改
push rax        ; RSP -= 8,将 RAX 存入栈
pop rbx ; 从栈读取到 RBX,RSP += 8

RBP/EBP - 栈帧基址指针

  • 指向当前栈帧的基址
  • 用于访问局部变量和参数
push rbp
mov rbp, rsp
sub rsp, 32 ; 分配 32 字节局部变量空间
; 访问局部变量:[rbp-8], [rbp-16] 等
; 访问参数:[rbp+16], [rbp+24] 等

新增寄存器 R8-R15

x86-64 新增了 8 个通用寄存器 R8-R15,这些寄存器:

  • 完全通用,没有特殊用途
  • 减少了内存访问的需求
  • 在调用约定中用于传递参数
mov r8, 100
mov r9, 200
add r8, r9 ; R8 = 300

段寄存器

段寄存器用于内存分段管理,在 16 位和 32 位保护模式下有重要作用。

段寄存器列表

寄存器名称用途
CS代码段寄存器存放代码段选择子
DS数据段寄存器存放数据段选择子
SS栈段寄存器存放栈段选择子
ES附加段寄存器字符串操作目标段
FS附加段寄存器线程本地存储
GS附加段寄存器线程本地存储

64 位模式下的段寄存器

在 x86-64 长模式下:

  • CS、DS、ES、SS 的基址被强制为 0
  • FS 和 GS 仍可用于线程本地存储(TLS)
  • 大多数情况下不需要显式操作段寄存器
; 访问线程本地存储(Linux)
mov rax, fs:0 ; 读取 TLS 基址

标志寄存器

RFLAGS(64 位)或 EFLAGS(32 位)寄存器存储处理器状态和运算结果标志。

标志位布局

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│...│IOPL│NT│...│RF│VM│AC│VIF│VIP│ID│ │ │ │ │ │ │ │
├───┴───┴───┴───┴───┴───┴───┴───┴───┴───┼───┼───┼───┼───┼───┼───┤
│ │OF│DF│IF│TF│SF│ZF│ │AF│
├───────────────────────────────────────┴───┴───┴───┴───┴───┼───┼───┤
│ │PF│ │CF│
└───────────────────────────────────────────────────────────┴───┴───┘

常用标志位

状态标志(反映运算结果)

标志名称含义
CF进位标志无符号运算溢出
ZF零标志结果为零
SF符号标志结果为负
OF溢出标志有符号运算溢出
PF奇偶标志结果中 1 的个数为偶数
AF辅助进位标志低 4 位进位

控制标志

标志名称含义
DF方向标志字符串操作方向(0=递增,1=递减)
IF中断标志是否响应可屏蔽中断

标志位使用示例

; 加法运算影响标志位
mov rax, 0xFFFFFFFFFFFFFFFF
add rax, 1 ; 结果为 0
; CF = 1(进位)
; ZF = 1(结果为零)
; SF = 0(结果非负)
; OF = 0(无符号溢出,但有符号不溢出)

; 比较操作
cmp rax, rbx ; 执行 RAX - RBX,设置标志位但不保存结果
jl less_than ; 如果 SF != OF,跳转(有符号小于)

; 方向标志控制字符串操作
cld ; DF = 0,字符串操作递增
std ; DF = 1,字符串操作递减

条件码与标志位关系

条件码含义标志位条件
ZF=1等于/零ZF = 1
ZF=0不等于/非零ZF = 0
CF=1无符号小于/进位CF = 1
CF=0无符号大于等于CF = 0
SF=OF有符号大于等于SF = OF
SF≠OF有符号小于SF ≠ OF

指令指针

RIP(64 位)或 EIP(32 位)寄存器存储下一条要执行的指令地址。

RIP 的特点

  • 不能直接修改,只能通过控制流指令间接修改
  • 在顺序执行时自动增加
  • 被跳转、调用、返回等指令修改
; 获取当前 RIP(x86-64 特有)
lea rax, [rip] ; RAX = 当前指令地址

; 相对跳转
jmp label ; RIP = label 地址

; 函数调用
call function ; RIP = function 地址,返回地址入栈

位置无关代码

RIP 相对寻址使得编写位置无关代码变得简单:

; 访问全局变量(位置无关)
lea rax, [rip + global_var] ; 加载全局变量地址
mov rbx, [rax]

; 调用函数(位置无关)
call [rip + function_ptr] ; 通过 RIP 相对地址调用

控制寄存器

控制寄存器用于控制处理器的操作模式,只能在特权级 0(内核模式)下访问。

主要控制寄存器

寄存器名称主要用途
CR0控制寄存器 0保护模式使能、分页使能、缓存控制
CR2控制寄存器 2页错误线性地址
CR3控制寄存器 3页目录基址
CR4控制寄存器 4各种架构扩展使能
; 读取控制寄存器(内核代码)
mov rax, cr0

; 写入控制寄存器
mov cr0, rax

模型特定寄存器(MSR)

MSR 是处理器特定的寄存器,用于控制和报告处理器性能。

; 读取 MSR
mov rcx, 0xC0000082 ; MSR 地址
rdmsr ; 结果在 EDX:EAX

; 写入 MSR
mov rcx, 0xC0000082
wrmsr ; 写入 EDX:EAX 到 MSR

调用约定与寄存器使用

System V AMD64 ABI(Linux/macOS)

寄存器用途保存者
RAX返回值-
RDI第 1 个参数调用者
RSI第 2 个参数调用者
RDX第 3 个参数调用者
RCX第 4 个参数调用者
R8第 5 个参数调用者
R9第 6 个参数调用者
R10-R11临时寄存器调用者
RBX通用寄存器被调用者
RBP栈帧指针被调用者
R12-R15通用寄存器被调用者

Microsoft x64 调用约定(Windows)

寄存器用途保存者
RAX返回值-
RCX第 1 个参数调用者
RDX第 2 个参数调用者
R8第 3 个参数调用者
R9第 4 个参数调用者
R10-R11临时寄存器调用者
RBX, RBP, RDI, RSI, R12-R15通用寄存器被调用者

函数调用示例

; Linux 调用约定
; int add(int a, int b, int c)
; 参数:RDI=a, RSI=b, RDX=c
; 返回值:RAX
add_three:
mov eax, edi ; EAX = a
add eax, esi ; EAX = a + b
add eax, edx ; EAX = a + b + c
ret

; 调用示例
mov edi, 10
mov esi, 20
mov edx, 30
call add_three ; RAX = 60

小结

本章介绍了 x86 架构的寄存器模型:

  • 通用寄存器:16 个 64 位寄存器,支持 8/16/32/64 位访问
  • 段寄存器:用于内存分段,64 位模式下作用有限
  • 标志寄存器:存储运算结果标志和处理器状态
  • 指令指针:指向下一条指令地址
  • 控制寄存器:控制处理器行为(内核模式)

理解寄存器模型是编写高效汇编代码的基础。下一章将学习 x86 的基础指令。