Meh*_*dad 85 x86 assembly cpu-registers
所以我知道以下寄存器及其用途应该是什么:
CS =代码段(用于IP)
DS =数据段(用于MOV)
ES =目标段(用于MOVS等)
SS =堆栈段(用于SP)
但是以下哪些寄存器用于什么?
FS ="文件段"?
GS = ???
注意:我不是在询问任何特定的操作系统 - 我问的是CPU的用途是什么,如果有的话.
Ira*_*ter 92
它们的目的是什么,以及它们用于Windows和Linux的用途.
段寄存器背后的初衷是允许程序访问许多不同(大)的内存段,这些内存段旨在独立并且是持久性虚拟存储的一部分.这个想法取自1966年的Multics操作系统,它将文件视为简单的可寻址内存段.没有BS"打开文件,写入记录,关闭文件",只是"将此值存储到该虚拟数据段",脏页刷新.
我们目前的2010年操作系统是一个巨大的倒退,这就是为什么他们被称为"太监".你只能解决您的进程空间的单段,给人一种所谓的"平(恕我直言沉闷)地址空间".x86-32机器上的段寄存器仍然可以用于真正的段寄存器,但没有人感到困扰(前任英特尔总裁安迪格罗夫在上个世纪有一个相当着名的公共场合,当他在所有英特尔工程师花费能量和他实现这个功能的钱,没有人会用它.去吧,安迪!)
AMD进入64位后决定他们不关心是否将Multics作为一种选择(这是慈善解释;不可靠的是他们对Multics一无所知),因此在64位模式下禁用了段寄存器的一般功能.仍然需要线程来访问线程本地存储,并且每个线程需要一个指针......在可立即访问的线程状态中的某处(例如,在寄存器中)...来线程本地存储.由于Windows和Linux在32位版本中都使用FS和GS(感谢Nick澄清),AMD决定让64位段寄存器(GS和FS)基本上只用于此目的(我认为你可以让它们指向您的进程空间中的任何位置;如果应用程序代码可以加载它们,则不知道.英特尔在恐慌中没有失去64位的AMD市场份额,而安迪退休后,决定只复制AMD的计划.
如果让每个线程的内存映射都有一个绝对的虚拟地址(例如,0-FFF),那就是它的线程本地存储(不需要[segment]寄存器指针!),这在结构上更漂亮了.我在20世纪70年代的8位操作系统中做到了这一点,它非常方便,就像有另一大堆寄存器一样.
因此,段寄存器现在有点像你的附录.它们具有退化目的.为了我们的集体损失.
那些不了解历史的人注定不会重演; 他们注定要做一些笨蛋.
cyt*_*nus 39
寄存器FS
和GS
段寄存器.它们没有处理器定义的目的,而是由操作系统运行它们来实现目的.在Windows 64位中,GS
寄存器用于指向操作系统定义的结构. FS
并且GS
OS内核通常使用它来访问特定于线程的内存.在Windows中,GS
寄存器用于管理特定于线程的内存.linux内核用于GS
访问特定于cpu的内存.
Raf*_*ahn 12
\n\n\xe2\x80\x9cFS\xe2\x80\x9d/\xe2\x80\x9cGS\xe2\x80\x9d 寄存器的用途是什么?
\n
只是访问默认数据段(DS)之外的数据。和ES一模一样。
\n\n\n所以我知道以下寄存器及其用途应该是什么:
\n[...]
\n
嗯,差不多了,但是 DS 不是“某些”数据段,而是默认的数据段。所有操作均默认进行 (*1)。这是所有默认变量所在的位置 - 本质上data
是 和bss
。在某种程度上,这也是 x86 代码相当紧凑的部分原因。所有基本数据(即最常访问的数据)(加上代码和堆栈)都在 16 位速记距离内。
ES 用于访问其他所有内容 (*2),即超过 64 KiB DS 的所有内容。就像文字处理器的文本、电子表格的单元格或图形程序的图片数据等等。与通常假设的不同,这些数据没有得到那么多的访问,因此需要前缀比使用更长的地址字段带来的伤害要小。
\n类似地,在进行字符串操作时可能必须加载(和重新加载)DS 和 ES,这只是一个小烦恼 - 这至少被当时最好的字符处理指令集之一所抵消。
\n真正令人痛苦的是当用户数据超过 64 KiB 并且必须开始操作时。虽然某些操作只是一次对单个数据项完成(想想A=A*2
),但大多数操作需要两个 ( A=A*B
) 或三个数据项 ( A=B*C
)。如果这些项驻留在不同的段中,则每次操作 ES 将重新加载多次,从而增加相当多的开销。
一开始,对于来自 8 位世界 (*3) 的小程序和同样小的数据集,这没什么大不了的,但它很快就成为一个主要的性能瓶颈 - 对于程序员来说更是一个真正的痛苦(和编译器)。在 386 中,英特尔最终通过添加两个段来缓解压力,因此任何系列一元、二元或三元运算(元素分布在内存中)都可以进行,而无需始终重新加载 ES。
\n对于编程(至少在汇编中)和编译器设计来说,这是一个很大的收获。当然,还可以更多,但有了三个,瓶颈就基本消失了,所以没必要做得太过分。
\n就命名而言,字母 F/G 只是 E 之后的字母延续。至少从 CPU 设计的角度来看,没有任何关联。
\n*1 - 使用 ES 作为字符串目标是一个例外,因为只需要两个段寄存器。如果没有它们,它们就没有多大用处——或者总是需要一个段前缀。这可能会扼杀令人惊讶的功能之一,即使用(非重复的)字符串指令,由于其单字节编码而导致极高的性能。
\n*2 - 所以事后看来,“Everything Else Segment”将是比“Extra Segment”更好的命名方式。
\n*3 - 始终要记住,8086 只是在8800完成之前作为权宜之计,主要用于嵌入式世界,以留住 8080/85 客户,这一点始终很重要。
\nFS用于指向Windows进程上的线程信息块(TIB)。
一个典型的例子是(SEH),它存储了一个指向回调函数的指针 FS:[0x00]
。
GS通常用作指向线程本地存储(TLS)的指针。您之前可能会看到的一个示例是堆栈金丝雀保护(stackguard),在gcc中,您可能会看到以下内容:
mov eax,gs:0x14
mov DWORD PTR [ebp-0xc],eax
Run Code Online (Sandbox Code Playgroud)
根据 Intel 手册,在 64 位模式下,这些寄存器旨在用作某些线性地址计算中的附加基址寄存器。我从第 3.7.4.1 节(第 4 卷集中的第 86 页)中提取了此内容。通常当CPU处于该模式时,线性地址与有效地址相同,因为该模式下通常不使用分段。
因此,在这个平面地址空间中,FS 和 GS 不仅在寻址本地数据方面发挥作用,而且在寻址某些操作系统数据结构(第 2793 页,第 3.2.4 节)方面发挥作用,因此这些寄存器旨在由操作系统使用,但是那些特定的设计者决定。
在 32 位和 64 位模式下使用覆盖时存在一些有趣的技巧,但这涉及特权软件。
从“初衷”的角度来看,很难说它们只是额外的寄存器。当CPU处于实地址模式时,就像处理器作为高速8086运行一样,这些寄存器必须由程序显式访问。为了实现真正的 8086 仿真,您可以在虚拟 8086 模式下运行 CPU ,并且不会使用这些寄存器。