2

在微软的网站上可以找到一些细节

__addgsbyte  ( offset, data )
__addgsword  ( offset, data )
__addgsdword ( offset, data )
__addgsqword ( offset, data )

内在功能。据说offset

从 GS 开头的偏移量。我假设GS指的是处理器寄存器。

GS与堆栈有什么关系(如果有的话)?或者,我如何计算相对于GS的偏移量?

(而且,是否有任何与此和特定调用约定相关的“陷阱”,例如__fastcall?)

4

3 回答 3

1

GS 寄存器根本与堆栈无关,因此与 callign 约定无关。在 x64 版本的 Windows 上,它用于指向操作系统数据:

来自维基百科

与 Windows NT 系列 x86 版本上的 FS 段描述符不同,GS 段描述符用于指向两个操作系统定义的结构:用户模式中的线程信息块 (NT_TIB) 和内核模式中的处理器控制区域 (KPCR)。因此,例如,在用户模式下,GS:0 是线程信息块的第一个成员的地址。保持这种约定使 x86-64 端口更容易,但要求 AMD 在长模式下保留 FS 和 GS 段的功能——即使任何现代操作系统都没有真正使用分段寻址本身。

请注意,这些内在函数仅在内核模式下可用(例如设备驱动程序)。要计算偏移量,您需要知道 GS 指向的内存段。因此,在内核模式下,您需要知道处理器控制区域的布局。

我个人不知道这些有什么用。

于 2011-11-24T18:05:41.143 回答
1

除了访问特定于操作系统的数据之外,这些内在函数以及 fs 对应物没有真正的用途,因此很可能添加这些纯粹是为了使 Windows 开发人员的生活更轻松(我个人将其用于内联 TLS 访问)

于 2011-11-24T20:08:52.853 回答
1

您链接的文档说:

将值添加到由相对于 GS 段开头的偏移量指定的内存位置。

这意味着它是这个 asm 指令的内在属性:(具有 GS 段覆盖add gs:[offset], data的普通内存目标add)与您选择的操作数大小。

编译器大概可以为offset部件选择任何寻址模式,并且data可以是寄存器或立即数,因此偏移量和数据中的一个或两个可以是运行时变量或常量。

实际访问的线性(虚拟)地址将是gs_base + offset,其中 gs_base 通过 MSR 设置为任何地址(由操作系统自行设置,或由您进行系统调用)。

至少在用户空间中,Windows 通常将 GS 用于 TLS(线程本地存储)。声称此内在函数仅适用于内核代码的答案是错误的。它不会添加GS 基址,它会在相对于现有 GS 基址的地址处添加到内存中。

MS 似乎只记录了 x64 的这种内在特性,但它也是 32 位模式下的有效指令。IDK 为什么他们会费心限制它。(当然除了 qword 形式:64 位操作数大小在 32 位模式下不可用。)


也许编译器不知道如何将__readgsdword/ (对该数据的操作) /优化__writegsdword为具有相同 gs:offset 地址的内存目标指令。如果是这样,这个内在将只是代码大小的优化。

但也许有时强制编译器将其作为一条指令执行以使其成为原子 wrt 有时是相关的。此内核上的中断(但包括其他 CPU 内核的访问)。IDK 如果这是一个预期的用例;这个答案只是解释了一行文档在 x86 asm 和内存分段方面的含义。

于 2021-02-09T10:41:14.397 回答