hel*_*lwq 6 assembly x86-64 linux-kernel memory-segmentation
我试图弄清楚Linux内核中MACRO当前的细节.当前的最终汇编代码是:
movq %%gs:0xb000,%0
Run Code Online (Sandbox Code Playgroud)
上面的代码可以工作!但是当我打印%% gs时,它的值为0,所以%% gs指向GDT NULL的第一项!! 这个怎么运作?
mov %%gs, %0
Run Code Online (Sandbox Code Playgroud)
相反,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);
Run Code Online (Sandbox Code Playgroud)
我的问题是:
%gs指向GDT NULL的第一项!! ?? 如何从MSR_GS_BASE读取它是一个CPU功能?我需要一些关于此的参考.
从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)+ displacement.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位模式下受支持.