我试图找出MACRO电流的细节在Linux内核中。 电流的最终装配的代码是:
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功能吗?我需要一些有关此引用。
从AMD架构程序员手册第2卷:系统编程 ,第4.5.3节:
FS和GS寄存器在64位模式。 不同于CS,DS,ES,SS和段,FS和GS段重写可以在64位模式下使用。 当FS和GS段覆盖在64位模式下的使用,它们各自的基地址在有效地址(EA)计算中使用。 然后将完整的EA计算变得(FS或GS).base +碱+(规模*指数)+位移。 的FS.base和GS.base值也被扩展到了完整的64位虚拟地址的尺寸,如图4-5所示。 将所得EA计算允许跨正极和负极地址来包装。
[...]
有两种方法来更新FS.base和GS.base隐藏描述字段的内容。 第一种是只提供给特权软件(CPL = 0)。 该FS.base和GS.base隐藏的描述符寄存器字段映射到的MSR。 特权软件可以使用单个WRMSR指令加载规范形式进入FS.base或GS.base 64位基地址。 该FS.base MSR地址是C000_0100h而GS.base MSR地址是C000_0101h。
(当实现支持,并通过设置CR4 [FSGSBASE]启用)更新FS和GS碱字段的第二种方法是提供给在任何特权级别上运行的软件。 该WRFSBASE和WRGSBASE指令的GPR的内容分别复制到FS.base和GS.base领域。 当操作数大小是32位,所述基座的上部双字被清除。 WRFSBASE和WRGSBASE在64位模式只支持。