操作系统-2.X86寄存器详解
1.什么是寄存器
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果以及一些CPU运行需要的信息
x86架构CPU走的是复杂指令集(CISC)
路线,提供了丰富的指令来实现强大的功能,与此同时也提供了大量寄存器来辅助功能实现。寄存器分为两类,一类对程序员不可见,这一类寄存器用于支撑CPU内部运行,程序员无法操作。一类对程序员可见,在进行汇编编写程序时,能够直接操作。
- 通用寄存器:
EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP
- 标志寄存器:
EFLAGS
- 指令寄存器:
EIP
- 段寄存器:
CS、DS、ES、FS、GS、SS
- 控制寄存器:
CR0、CR1、CR2、CR3、CR4
- 调试寄存器:
DR0、DR1、DR2、DR3、DR4、DR5、DR6、DR7
- 描述符寄存器:
GDTR、IDTR、LDTR、TR
2.实模式下寄存器(16bit)
在x86架构下,实模式可以使用的通用寄存器有 AX、BX、CX、DX、SI、DI、BP
和 SP
。这些寄存器都是16位的,可以分为两个8位的寄存器来使用。
此外,还有一些特殊用途的寄存器,包括:
IP
(指令指针寄存器):保存当前执行的指令地址。CS
(代码段寄存器):保存代码段的起始地址。DS
(数据段寄存器):保存数据段的起始地址。ES
(附加段寄存器):附加数据段的起始地址。GS
(附加段寄存器):附加数据段的起始地址。FS
(附加段寄存器):附加数据段的起始地址。SS
(堆栈段寄存器):保存堆栈段的起始地址。FLAGS
(标志寄存器):包含各种标志位,如零标志、进位标志、符号标志等
其中FS
,GS
附加段寄存器是在32位CPU中增加的,但是在32位CPU中在实模式下同样可以使用,因为32位CPU兼容16位CPU的特性。
16位寄存器 | 功能 | 高8位 | 低8位 |
---|---|---|---|
AX |
累加寄存器,常用于算术运算,保存与外设输入输出的数据 | AH |
AL |
CX |
计数寄存器,常用于循环指令中的循环次数 | CH |
CL |
DX |
数据寄存器,通常情况下只用于保存外设控制器的端口号地址 | DH |
DL |
BX |
基址寄存器,来存储内存地址,段基址为DS | BH |
BL |
SP |
栈指针寄存器,段基址为SS,用来指向栈顶 | ||
BP |
栈帧的基址寄存器,段基址为SS | ||
SI |
源变址寄存器,存储数据源地址,段基址为DS | ||
DI |
目的变址寄存器,存储数据目的地址,段基址为DS |
BP指向栈底,SP指向栈顶,两者共同维护了栈空间。
push
和pop
可更改SP
的值,sp
指针的值会自动更新
2.1 寄存器用法举例
SI、DI
mov ecx, 10 ; 设置循环计数为10
mov esi, 0 ; 设置SI寄存器为0作为初始值
mov edi, 100 ; 设置DI寄存器为100作为初始值
loop_start:
mov eax, [esi] ; 从源地址(SI)读取数据到EAX寄存器
mov [edi], eax ; 将数据存储到目的地址(DI)
add esi, 4 ; 增加SI的值,以便读取下一个双字
add edi, 4 ; 增加DI的值,以便存储到下一个地址
loop loop_start ; 循环,减少ECX计数,直到为零在这个例子中,SI和DI寄存器用作源地址和目的地址。循环从源地址读取数据,然后将其存储到目的地址,然后递增SI和DI以访问下一个元素。通过loop指令和ECX计数器,循环执行直到计数为零。
BP、SP
push ebp ; 保存当前函数的旧的基址到堆栈中
mov ebp, esp ; 将当前堆栈指针存储到基址指针寄存器BP中
sub esp, 16 ; 分配16字节的局部变量空间
mov dword ptr [ebp-4], 10 ; 将值10存储到基址指针寄存器BP-4指向的位置(局部变量)
mov eax, dword ptr [ebp-4] ; 从基址指针寄存器BP-4指向的位置读取值到EAX寄存器
add esp, 16 ; 释放局部变量空间
pop ebp ; 恢复旧的基址到基址指针寄存器BP中
3.保护模式下寄存器(32bit)
3.1 保护模式寄存器介绍
在32位保护模式下,x86架构提供了更多的通用寄存器以及扩展功能。以下是32位保护模式下可以使用的寄存器:
- 通用寄存器(General Purpose Registers):
EAX
:累加器寄存器(Accumulator Register)。EBX
:基址寄存器(Base Register)。ECX
:计数寄存器(Counter Register)。EDX
:数据寄存器(Data Register)。ESI
:源索引寄存器(Source Index Register)。EDI
:目的索引寄存器(Destination Index Register)。EBP
:基址指针寄存器(Base Pointer Register)。ESP
:堆栈指针寄存器(Stack Pointer Register)。
- 扩展通用寄存器:
EIP
:指令指针寄存器(Instruction Pointer Register)。EFLAGS
:标志寄存器(Flags Register),用于存储各种标志位,如零标志、进位标志、符号标志等。
- 段寄存器(Segment Registers):
CS
:代码段寄存器(Code Segment Register)。DS
:数据段寄存器(Data Segment Register)。ES
:附加段寄存器(Extra Segment Register)。FS、GS、SS
:附加段寄存器,用于访问额外的数据段。
- 控制寄存器(Control Registers):
CR0、CR2、CR3、CR4
:用于控制和管理保护模式的特性,如分页机制、特权级等。
- 段描述符寄存器(Descriptor Registers):
GDTR
:全局描述符表寄存器(Global Descriptor Table Register)。IDTR
:中断描述符表寄存器(Interrupt Descriptor Table Register)。LDTR
:局部描述符表寄存器(Local Descriptor Table Register)。TR
:任务寄存器(Task Register)。
3.2 控制寄存器
3.2.1 CR0
寄存器
PE: Protection Enble
当此位为0,代表在CPU处在实模式,此位为1,表示CPU处在保护模式;从实模式切换到保护模式时需要将此位置为1.
mov eax, cr0
or eax, 0x00000001
mov cr0, eaxTS:Task Switched
WP:Write Protect
对于Intel 80486或以上的CPU,CR0的位16是写保护(Write Proctect)标志。当设置该标志时,处理器会禁止超级用户程序(例如特权级0的程序)向用户级只读页面执行写操作;当该位复位时则反之。该标志有利于UNIX类操作系统在创建进程时实现写时复制(Copy on Write)技术。
AM:Alignment Mask
NW:Not Writethrough
CD:Cache Disable
PG:Paging
是否启动分页机制的位,只有在保护模式以上才能开启分页机制。PG位为1开启分页机制,PG位为0关闭分页机制
在CPU刚上电时,处理器被复位成PE=0,PG=0。
3.2.2 CR2
寄存器
3.2.3 CR3
寄存器
3.2.4 CR4
寄存器
3.3 EFLAGS
寄存器
- CF:进位标志
- PF:奇偶位标志
- AF:辅助进位标志
- ZF:零标志位
- SF:符号标注位
- TF:陷阱标志位
- IF:中断标志位。若IF为1,表示中断开启;若为0,表示中断关闭
- DF:方向标志位。
- OF:溢出标志位。
- IOPL:特权级标志位,占2个bit,标志了4个特权级
- NT:任务嵌套标志位
- RF:恢复标志位
- VM:虚拟8086模式
- AC:对齐检查
- VIF:虚拟中断标志位
- VIP:虚拟中断挂起标志位
- ID:识别标志位
- 22~31:没有实际用途,占位用,为了将来拓展
3.4 段描述符寄存器
3.4.1 GDTR
寄存器
GDTR是个48位的寄存器,专门用来储存GDT的内存地址和大小
GDT:Global Descriptor Table,全局段描述符,在保护模式下,GDT在内存中有且只有一个,GDT的数据结构如下,每个描述符8个字节,64个bit,可以存放在内存当中任意位置,addr相当于GDT的内存起始地址,GDT的总长度就就是GDT界限
段描述符的主要属性都在高32位:
0~7位:段基址的16-23
24~31位:段基址的24-31
8~11位:type字段,共四位,用来指定本描述符的类型
12位:S字段,用于指示系统是否是系统段。S为0表示系统段,S为1表示数据段,type字段要和S字段配合在一起才能确定段描述符的确切类型。
15位:Present,即段是否存在。如果段存在于内存中,P为1,否则为0
16~19位:段界限的16-19位
20位:AVL,随便用,操作系统可以随便用这一位
21位:L字段,用来设置是否是64位代码段。L为1表示64位代码段,否则表示32位代码段。
22位:D/B字段
23位:G字段,用来设置段界限的单位大小,若G为0,表示段界限的单位是4KB,若界为1,表示段界限的单位是4KB
24~31位:段基址的最后8位
在实模式下,段寄存器中存储的是段基地址,即内存段的起始地址,而在保护模式下,由于段基址已经存入了段描述符中,所以段寄存器不再存放段基址,而是存放一个叫选择子的东西,选择子用来在段描述符表中索引相应的段描述符,数据结构如下:
- 0~1位:RPL,存储请求特权级,总共有0、1、2、3四个特权级
- 2位:TI,用来表示是GDT还是LDT,TI为0表示在GDT中索引描述符,TI为1表示在LDT中索引描述符
在代码中我们可以定义对应的结构体来定义GDT和选择子以及全局描述符表指针
// 全局描述符 |
下一步就是填充GDT和GDT_PTR
// 填充GDT |
然后使用lgdt命令将全局描述符表指针加载到GDTR寄存器中:
lgdt [gdt_ptr] |
3.4.2 IDTR
寄存器
idtr寄存器用于存储中断描述符表的地址和表界限
在中断描述符表中可以存储的是中断描述符,这里的中断描述符分为四类,以不同门的叫法来描述,在上面描述GDT的时候,提到S字段和type字段一起决定了这个描述符是什么,对于GDT来说,我们设置S位为1,代表非系统段,对于中断描述符来说需要将S位设为0,由此延申出了四种描述符:
- 任务门描述符
任务门和任务状态段 (Task Status Segment,TSS) 是Intel处理器在硬件一级提供的任务切换机制,所以任务门需要和TSS配合在一起使用,在任务门中记录的是TSS选择子,偏移量未使用。任务门可以存在于全局描述符表GDT、局部描述符表LDT、中断描述符表IDT中。描述符中任务门的type值为二进制0101,其结构如下图所示。顺便说一句大多数操作系统 (包括Linux) 都未用TSS实现任务切换
- 中断门描述符
中断门包含了中断处理程序所在段的段选择子和段内偏移地址。当通过此方式进入中断后,标志寄存器eflags中的IF位自动置0,也就是在进入中断后,自动把中断关闭,避免中断嵌套。Linux就是利用中断门实现的系统调用,就是那个著名的int0x80。中断门只允许存在于IDT中。描述符中中断门的type值为二进制1110,其结构如下图所示
- 陷阱门描述符
陷阱门和中断门非常相似,区别是由陷阱门进入中断后,标志寄存器eflags中的IF位不会自动置0。陷阱门只允许存在于IDT中。描述符中陷阱门的type值为二进制1111。其结构如下图所示
- 调用门描述符
调用门是提供给用户进程进入特权0级的方式,其DPL为3。调用门中记录例程的地址,它不能用int指令调用,只能用call和imp指令。调用门可以安装在GDT和LDT中。描述符中调用门的type值为二进制1100。其结构如下图所示
同样我们可以使用一个结构体来描述中断描述符:
typedef struct gate_t |
然后填充中断描述符和中断
typedef void* handler_t; // 中断处理函数 |
最后将idt_ptr填充进IDTR寄存器中
//加载中断描述符表 |
3.4.3 LDTR
寄存器
3.4.4 TR
寄存器
4.长模式下寄存器(64bit)
在长模式下,也称为64位保护模式(64-bit Protected Mode)或x86-64架构,x86处理器提供了更广泛的寄存器集合。以下是长模式下可以使用的寄存器:
- 通用寄存器(General Purpose Registers):
RAX
:累加器寄存器(Accumulator Register)。RBX
:基址寄存器(Base Register)。RCX
:计数寄存器(Counter Register)。RDX
:数据寄存器(Data Register)。RSI
:源索引寄存器(Source Index Register)。RDI
:目的索引寄存器(Destination Index Register)。RBP
:基址指针寄存器(Base Pointer Register)。RSP
:堆栈指针寄存器(Stack Pointer Register)。R8-R15
:扩展的通用寄存器。
- 扩展通用寄存器:
RIP
:指令指针寄存器(Instruction Pointer Register)。RFLAGS
:标志寄存器(Flags Register),包含各种标志位。
- 段寄存器(Segment Registers):
CS
:代码段寄存器(Code Segment Register)。DS
:数据段寄存器(Data Segment Register)。ES
:附加段寄存器(Extra Segment Register)。FS、GS、SS
:附加段寄存器,用于访问额外的数据段。
- 控制寄存器(Control Registers):
CR0、CR2、CR3、CR4、CR8
:用于控制和管理保护模式的特性,如分页机制、特权级等。
- 段描述符寄存器(Descriptor Registers):
GDTR
:全局描述符表寄存器(Global Descriptor Table Register)。IDTR
:中断描述符表寄存器(Interrupt Descriptor Table Register)。LDTR
:局部描述符表寄存器(Local Descriptor Table Register)。TR
:任务寄存器(Task Register)。
- XMM寄存器(SSE寄存器):
XMM0-XMM15
:128位的向量寄存器,用于执行SSE(Streaming SIMD Extensions)指令集中的向量运算。
- YMM寄存器(AVX寄存器):
YMM0-YMM15
:256位的向量寄存器,用于执行AVX(Advanced Vector Extensions)指令集中的向量运算。
- ZMM寄存器(AVX-512寄存器):
ZMM0-ZMM31
:512位的向量寄存器,用于执行AVX-512指令集中的向量运算。