我尝试了解 Linux 上 i386 和 amd64 架构的内存分段过程。这似乎与段寄存器%fs
, %gs
, %cs
, %ss
, %ds
,密切相关%es
。
有人可以解释如何在用户和内核程序中使用这些寄存器吗?
我尝试了解 Linux 上 i386 和 amd64 架构的内存分段过程。这似乎与段寄存器%fs
, %gs
, %cs
, %ss
, %ds
,密切相关%es
。
有人可以解释如何在用户和内核程序中使用这些寄存器吗?
内核视角:
我将尝试从内核的角度来回答,涵盖各种操作系统。
内存分段是访问内存区域的旧方法。所有主要的操作系统,包括 OSX、Linux(从 0.1 版开始)和 Windows(从 NT 开始)现在都在使用分页,这是访问内存的更好方式(恕我直言)。
英特尔一直在其处理器中引入向后兼容性(IA-64 除外,我们看到它是如何失败的......)因此,在其初始状态(重置后),处理器以称为实模式的模式启动,在这种模式下,默认情况下启用分段以支持旧软件。在操作系统启动过程中,处理器进入保护模式,然后启用分页。
在分页之前,段寄存器是这样使用的
在实模式下,每个逻辑地址直接指向物理内存位置,每个逻辑地址由两个 16 位部分组成: 逻辑地址的段部分包含一个段的基地址,粒度为 16 字节,即一个段可以从物理地址 0, 16, 32, ..., 2 20 -16。逻辑地址的偏移量部分包含段内部的偏移量,即物理地址可以计算为
physical_address := segment_part × 16 + offset
(如果地址线A20启用),分别(如果A20关闭)每个段的大小为2 16字节。[维基百科](segment_part × 16 + offset`) mod 220
让我们看一些例子(286-386时代):
286架构引入了4个段:CS(代码段)DS(数据段) SS(堆栈段)ES(额外段) 386架构引入了两个新的通用段寄存器FS、GS。
典型的汇编操作码(采用 Intel 语法)如下所示:
mov dx, 850h
mov es, dx ; Move 850h to es segment register
mov es:cx, 15h ; Move 15 to es:cx
使用分页(保护模式),段寄存器不再用于寻址内存位置。
在保护模式下,
segment_part
它被一个 16 位选择器取代,选择器的高 13 位(第 3 位到第 15 位)包含描述符表内条目的索引。下一位(位 2)指定操作是与 GDT 还是 LDT 一起使用。选择器的最低两位(bit 1 和bit 0)组合起来定义请求的权限;其中值为 0 的优先级最高,值为 3 的优先级最低。[维基百科]
然而,这些段仍然用于在 GDT 中强制执行硬件安全
全局描述符表或 GDT 是英特尔 x86 系列处理器使用的一种数据结构,以 80286 开头,用于定义程序执行期间使用的各种内存区域的特征,包括基地址、大小和访问权限,如可执行性和可写性。这些内存区域在 Intel 术语中称为段。[维基百科]
因此,实际上保护模式下的段寄存器用于存储 GDT 的索引。
一些操作系统(例如 Windows 和 Linux)将某些段用于内部使用。例如,Windows x64 使用GS
寄存器访问 TLS(线程本地存储),而在 Linux 中它用于访问 cpu 特定内存。
用户视角:
从用户的角度来看,在最近使用分页的操作系统中,内存以所谓的“扁平模式”工作。每个进程以线性方式访问自己的内存(4GB),因此基本上不需要段寄存器。
它们仍然是寄存器,因此它们当然可以用于各种其他组装操作。
FS 指向异常处理链,CS 和 DS 由 OS 填充代码和数据段。SS 是电池/堆栈段。据我所知,GS 和 ES 是免费的。
内核模式还是用户模式应该无关紧要(它们被一些指令使用,例如 XLAT、MOVS 和其他一些指令,因此您必须以相同的方式使用它们),但以防万一我在谈论编程用户空间。
我以前没有注意到,但是您使用的是 %fs 符号,而不是 FS,所以您可能指的是 Linux,这是另一个故事(您也可以更清楚地了解保护/实模式)。您还可以从 stackexchange 的其他答案中看到,linux 在 FS 和 GS 中显然为您提供了“线程本地存储”和“处理器数据区”。CS、DS 和 SS 应该仍然是代码/数据/堆栈。
为了论证起见,我不知道您如何在 Mac 上使用这些寄存器。
对于 64 位,这取决于:如果不是在兼容模式下(您可以在其中执行 64 位和 32 位代码),那么 DS、ES 和 SS 将被忽略,并且像 POP SS 这样的指令会给出错误。没有分段(内存模型是扁平的),应该没有实模式(但我认为你只是指保护模式?),如果我没猜错的话,就没有硬件任务切换。
在 64 位模式下有关于 CS、FS 和 GS(特别是隐藏部分)的更多详细信息,但由于它不经常使用,所以最好省略它们。
您可以查看 AMD 系列处理器的手册,尤其是在 64 位传统模式的情况下:http :
//developer.amd.com/resources/documentation-articles/developer-guides-manuals/
我为一个被标记为重复和关闭的问题写了一个 Windows 特定的答案,关闭标志指的是这个线程,所以我在这里发布了一个答案
os win7 sp1 32 位机器
内核转储使用来自 sysinternals 的 livekd
一个 16 位的段寄存器包含
13 位选择器
1 位表描述符
2 位 requester_privilege_level
Selector tl rpl
0000000000000----0---00
所以 cs 和 fs 转换为二进制将是
kd> r cs;r fs
cs=00000008 = 0b 00001 0 00
fs=00000030 = 0b 00110 0 00
2 位 rpl 表示 0,1,2,3 环(所以 00 = 0 = 环零)
gdt = 1 位表示 0,1(0 表示GDT,1 表示LDT)
全局描述符表和局部描述符表
高 13 位代表段选择器
所以 cs = 0x08 有一个段选择器 0b 001 = 0x1 即 gdtr@1
& fs = 0x30 有一个段选择器 0f 0b 110 = 0x6 即 gdtr@6
内核 cs,fs 与用户 cs,fs 不同,从 Windbg 的 dg 命令可以看出
kd> dg @cs <<<<<<<--- kernel
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P Nl 00000c9b
0:000> dg @cs <<<<<<<<----user
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
001B 00000000 ffffffff Code RE Ac 3 Bg Pg P Nl 00000cfb
kd> dg @fs <<<<<<<<------- kernel
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0030 82f6dc00 00003748 Data RW Ac 0 Bg By P Nl 00000493
0:000> dg @fs
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
003B 7ffdf000 00000fff Data RW Ac 3 Bg By P Nl 000004f3
您可以从
osdevwiki_gdt robert-collins_ddj_article收集有关 gdt 的足够信息
我在这里使用 livekd 手动执行此操作
使用windbg你可以获得描述符和任务门寄存器
kd> rM 100
gdtr=80b95000 gdtl=03ff idtr=80b95400 idtl=07ff tr=0028 ldtr=0000
每个 gdtr 条目是 64 位,因此您可以有 7f 个 gdtr 条目,如您所见 gdtl 为 3ff 0x80*0x08-1 = 0x400-1 = 0x3ff(索引从 0 开始,而不是 1)
所以 gdtr 条目 @1,@2 是 @gdtr+(0x1*0x8) @gdtr+(0x2*0x08=0x10) 等等
kd> dq @gdtr+8 l1 gdtr@1 = gdtr+0n1*0x8 =0n8 = 0x8
80b95008 00cf9b00`0000ffff = gdtr+0n6*0x8 =0n48 = 0x30
kd> dq @gdtr+30 l1
80b95030 824093f6`dc003748
kd> dq @gdtr+38 l1
80b95038 7f40f3fd`e0000fff
让位游戏手动最后两个 gdtr 条目
-------------------------------------------------------------------------------------------
gdtrentry [63: [55: [51: [47: [39: [15:
56] 52] 48] 40] 16] 0]
base gdrs L p d t Base Base Limit
Hi rb0y h r l y Mid Low
-------------------------------------------------------------------------------------------
bit position 66665555 5555 5544 4 44 44444 33333333 3322222222221111 1111110000000000
32109876 5432 1098 7 65 43210 98765432 1098765432109876 5432109876543210
-------------------------------------------------------------------------------------------
824093f6dc003748 10000010 0100 0000 1 00 10011 11110110 1101110000000000 0011011101001000
as hex 0x82 0100 0 1 0 0x13 0xF6 0xDC00 0x3748
--------------------------------------- ---------------------------------------------------
7f40f3fde0000fff 01111111 0100 0000 1 11 10011 11111101 1110000000000000 0000111111111111
as hex 0x7F 0100 0 1 3 0x13 0xFD 0xE000 0x0FFF
-------------------------------------------------------------------------------------------