XV6

程序寄存器是唯一一个被所有过程共享的资源。虽然在给定时刻只能有一个过程是活动的,我们必须保证当一个过程(调用者)调用另一个(被调用者)时,被调用者不会覆盖某个调用者稍后会使用的寄存器的值。为此,IA32 (Intel Architecture 32 bit)采用了一组统一的寄存器使用惯例,所有的过程都必须遵守,包括程序库中的过程。

根据惯例,寄存器 EAX,EDX,ECX 被划分为调用者保存(caller save)寄存器。当过程 P 调用 Q 时,Q 可以覆盖这些寄存器,而不会破坏 P 所需要的数据。另外,寄存器 EBX,ESI 和 EDI 被划分为被调用者保存(callee save)寄存器。这意味着 Q 必须在覆盖它们之前,将这些寄存器的值保存到栈中,并在返回前恢复它们,因为 P(或某个更高层次的过程)可能会在今后的计算中需要这些值。此外,根据这里描述的惯例,必须保存寄存器 EBP,ESP。

如下面这段程序

int P(int x){
	int y = x * x;
	int z = Q(y);
	return y + z;
}

过程 P 在调用 Q 之前计算 y,但是它必须保证 y 的值在 Q 返回后是可用的。有两种方式可以做到这一点:

  1. 它可以在调用 Q 之前,将 y 的值存放在自己的栈帧中;当 Q 返回时,它可以从栈中取出 y 的值。
  2. 它可以将 y 的值保存在被调用者保存寄存器中。如果 Q,或任何其他 Q 调用的程序,想使用这个寄存器,它必须将这个寄存器的值保存在栈帧中,并在返回前恢复该值。因此,当 Q 返回到 P 时,y 的值会在被调用者保存寄存器中,或者是因为寄存器根本就没有改变,或者是因为它被保存并恢复了。

1. 寄存器汇总

寄存器 描述
通用寄存器 8 个 32 位,存放正在处理的数据
段寄存器 6 个 16 位,处理内存访问
指令寄存器 1 个 32 位,指向要执行的下一条指令码
浮点寄存器 8 个 80 位,存放浮点数据
控制寄存器 5 个 32 位,确定处理器的操作模式
调试寄存器 8 个 32 位,在调试处理器时包含信息
标志寄存器 EFLAGS

浮点寄存器和调试寄存器没有在 XV6 中使用。

通常 X86 对操作系统隐藏了缓存,所以我们只需要考虑寄存器和主存两种存储器,不用担心主存的层次结构引发的差异。

1.1 通用寄存器

通用寄存器 描述
EAX 用于操作数和结果数据的累加器
EBX 指向数据内存段的数据的指针
ECX 字符串和循环操作的计数器
EDX IO 指针
EDI(destination) 用于字符串操作的目标的数据指针
ESI(source) 用于字符串操作的源的数据指针
ESP(stack) 堆栈指针
EBP(base) 堆栈数据指针

EAX,EBX,ECX,EDX 可以通过 16 位,8 位名称引用。

|<------------EAX---------------->|
|1 2 3 4 5 6 7 8 |1 2 3 4 5 6 7 8 |
|----------------|-------|--------|
|. . . . . . . . |. AH . | . AL . |
|----------------|-------|--------|
. . . . . . . . .|<------AX------>|

1.2 段寄存器

IA32 允许 3 种访问系统内存的方法:

  1. 平坦内存模式:所有指令、数据、堆栈包含在相同的地址空间内,通线性地址访问每个内存位置。
  2. 分段内存模式:划分为 3 个段,指令段,数据段,堆栈段;内存位置通过逻辑地址定义,包含段地址和偏移地址;处理器将逻辑地址转换为线性地址。
  3. 实地址模式:所有段寄存器指向 0 线性地址,所以指令,数据,堆栈元素搜通过线性地址直接访问。
段寄存器 描述
CS(code segment) 代码段基地址。处理器根据 CS 值和 EIP 中的偏移值取指令
DS(data segment) 数据段基地址
ES(extra segment) 附加段指针
FS 同 ES
GS 同 ES
SS(stack segment) 堆栈段基地址;包含传递给函数和过程的数据值

1.3 指令寄存器

EIP(extended instruction pointer)跟踪要执行的下一条指令码,记录偏移值或者线性地址;不可直接修改。

1.4 控制寄存器

确定处理器的操作模式,以及当前正在处理任务的特性。

控制寄存器 描述
CR0 控制处理器状态和操作模式的系统
CR1 当前没有使用
CR2 内存页面错误信息
CR3 内存页面目录信息
CR4 支持处理器特性和说明处理器特性的标志

不能直接读取或写入,需要通用寄存器 “中转” 一下。

2. 标志寄存器

该寄存器比较复杂,单独拿出来讲。每个操作都要有一种机制确定操作是否成功,IA32 平台使用 1 个 32 位的 EFLAGS 包含一组状态,控制和系统标志。

2.1 状态标志

表明处理器进行的数学操作的结果。

标志 名称 描述
CF 0 进位标志 无符号整数运算最高有效位产生进位或借位,置 1
PF 2 奇偶校验标志 奇校验位,使得寄存器和此位 1 的数目为奇数个
AF 4 辅助进位标志 用于 BCD 码的运算
ZF 6 零标志 操作结果为 0,置 1
SF 7 符号标志 设置为结果的最高有效位
OF 11 溢出标志 带符号数运算溢出,置 1

2.2 控制标志

控制处理器的特定行为。

当前只定义了一个控制标志:DF 标志(direction flag),控制处理器处理字符串的方式。

DF 位置 1:字符串指令自动低递减内存地址,到达字符串的下一个字节。

DF 位置 0:字符串指令自动低递增内存地址一到达字符串的下一个字节。

2.3 系统标志

控制操作系统级别的操作,应用程序不应该试图修改系统标志。

标志 名称 描述
TF 8 陷阱标志 置 1 时,启用单步模式,每次执行一条指令,等待下一条指令执行的信号。调试汇编程序时极有用
IF 9 中断使能标志 控制处理器如何响应外部源接受到的信号
IOPL 12~13 IO 特权级别标志 表明当前正在运行的任务的 IO 权限级别
NT 14 嵌套任务标志 控制当前执行的任务是否链接到前一个执行的任务。用于链接被中断和被调用的任务
RF 16 恢复标志 控制处理器在调试模式如何响应异常
VM 17 虚拟 8086 状态标志 表明处理器在虚拟 8086 状态执行,而不是保护模式或实模式
AC 18 对准检查标志 和 CR0 的 AM 位一起用于启用内存引用的对准检查
VIF 19 虚拟中断标志 处理器在虚拟模式中操作时,起到 IF 标志位的作用
VIP 20 虚拟中断挂起标志 处理器在虚拟模式中操作时,标志一个中断正被挂起
ID 21 识别标志 表示处理器是否支持 CPUID 指令