Windows下编译为二进制的用户态程序输出逻辑地址还是线性地址?
结论
你在Windows 10 64位长模式(long mode)下运行示例代码打印出的变量a的地址,是完成GDT段转换后的线性地址(linear address),也就是后续送入分页单元映射为物理地址的虚拟地址。虽然长模式下逻辑地址和线性地址数值完全相等,但程序层面观测到的地址语义上属于线性地址,无法拿到段转换前的原始逻辑地址。
具体原理
- x86-64长模式对段机制做了大幅简化:除了FS、GS两个段寄存器保留给线程本地存储等特殊场景使用外,CS、DS、ES、SS这几个常用段的段基址被硬件强制设为0,段限长覆盖整个64位地址空间,本质是强制使用平坦内存模型。
- 原生x86地址转换流程中,逻辑地址转线性地址的计算规则是
线性地址 = 段基址 + 段内偏移,当段基址固定为0时,计算得到的线性地址和逻辑地址中的段内偏移值完全相等,这也是你了解到两者取值一致的原因。 - 段转换是CPU执行内存访问指令时硬件自动完成的固定流程,这个过程对上层应用完全透明,没有任何指令或接口能让用户态程序单独读取段转换前的原始逻辑地址。
- C语言中指针存储的地址值、
%p格式化输出的地址值,本身就对应CPU地址空间中的线性地址(也就是常说的用户态虚拟地址),不存在暴露原始逻辑地址的可能。
补充说明
很多人会疑惑:既然两个地址数值完全一样,区分逻辑地址和线性地址是不是没有意义?这个区分是Intel架构定义的地址转换流程的环节划分:逻辑地址是指令操作数中直接给出的寻址表示,线性地址是段转换单元的输出、同时是分页转换单元的输入。长模式下段转换步骤没有被取消,只是因为段基址为0,计算结果和输入的段内偏移没有差异而已。

内容的提问来源于stack exchange,提问作者caramel1995
相关产品推荐
相关产品推荐

