6

我试图找出 Linux 内核中当前 MACRO 的详细信息。current的最终汇编代码为:

movq %%gs:0xb000,%0

上面的代码可以工作!但是当我打印 %%gs 时,它的值为 0,所以 %%gs 指向 GDT NULL 的第一项!!??这个怎么运作?

mov %%gs, %0

相反,gs 的基数在 MSR_GS_BASE 中,当前可以替换为:

/*0xb000 is the offset of per_cpu__current_task*/
cur_task = (unsigned long*)(x86_rdmsr64(MSR_GS_BASE) + 0xb000);
println("cur_task:%p",*cur_task);

我的问题是:

%gs 指向 GDT NULL 的第一项!!?? 从 MSR_GS_BASE 读取它是如何工作的,它是 CPU 特性吗?我需要一些关于此的参考。

4

1 回答 1

11

来自AMD 架构程序员手册第 2 卷:系统编程,第 4.5.3 节:

64 位模式下的 FS 和 GS 寄存器。与 CS、DS、ES 和 SS 段不同,FS 和 GS 段覆盖可用于 64 位模式。在 64 位模式下使用 FS 和 GS 段覆盖时,它们各自的基地址用于有效地址 (EA) 计算。完整的 EA 计算则变为 (FS 或 GS​​).base + base + (scale * index) + 位移。FS.base 和 GS.base 值也扩展为完整的 64 位虚拟地址大小,如图 4-5 所示。生成的 EA 计算允许跨越正负地址。

[...]

有两种方法可以更新 FS.base 和 GS.base 隐藏描述符字段的内容。第一个专用于特权软件 (CPL = 0)。FS.base 和 GS.base 隐藏描述符寄存器字段映射到 MSR。特权软件可以使用单个 WRMSR 指令将规范形式的 64 位基地址加载到 FS.base 或 GS​​.base 中。FS.base MSR 地址是 C000_0100h,而 GS.base MSR 地址是 C000_0101h。

更新 FS 和 GS 基本字段的第二种方法适用于以任何特权级别运行的软件(当实现支持并通过设置 CR4[FSGSBASE] 启用时)。WRFSBASE 和 WRGSBASE 指令分别将 GPR 的内容复制到 FS.base 和 GS.base 字段。当操作数大小为 32 位时,基数的高位双字被清除。WRFSBASE 和 WRGSBASE 仅在 64 位模式下受支持。

于 2012-07-16T03:19:33.077 回答