我试图弄清楚Linux内核中MACRO电stream的细节。 当前最后的汇编代码是:
movq %%gs:0xb000,%0
上面的代码可以工作! 但是当我打印%% gs时,它的值是0,所以%% gs指向GDT NULL的第一项! 怎么运行的?
mov %%gs, %0
相反,gs的基础在MSR_GS_BASE中,并且当前可以被replace为:
/*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读取它是如何工作的,它是一个CPUfunction吗?我需要一些关于这个的参考。
从“ AMD体系结构程序员手册”卷2:系统编程 ,第4.5.3节:
FS和GS寄存器在64位模式下。 与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位模式下受支持。