You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核直接映射区虚拟地址转物理地址:测试输出异常原因咨询

内核虚拟地址转物理地址的疑惑与%p格式打印问题

我原本以为,将直接映射区的内核虚拟地址转换为物理地址时,只需减去page_offset_base(4级分页下为0xffff888000000000)。但测试时发现用kmalloc()申请内存后,用%lx和%p格式打印地址的结果低比特位差异很大,并非简单减法能得到的结果,想知道原因。

测试代码

buf_high = (char*)kmalloc(140, __GFP_HIGHMEM);
buf = (char*)kmalloc(140, GFP_KERNEL);

printk("kmalloc highmem : %lx, %p\n", buf_high, buf_high);
printk("kmalloc : %lx, %p\n", buf, buf);

测试输出

[ 1157.671135] kmalloc highmem : ffff888118d2b000, 000000009412a3d4
[ 1157.671142] kmalloc : ffff888118d2b3c0, 000000009ce9058c

问题解析

核心原因:%p在printk中的特殊处理

Linux内核的printk里,%p格式符并不是直接打印指针的原始值,而是会对指针进行地址混淆,目的是防止泄露内核地址信息,提升系统安全性。

  • %lx是按十六进制格式直接输出指针的真实虚拟地址值,也就是你看到的ffff888118d2b000这类地址。
  • %p则会通过内核的pointer_to_id()函数把指针转换成一个随机化的ID,这个ID和原始地址没有直接线性对应关系,所以看起来和%lx的结果差异极大。

关于直接映射区地址转换的补充

你最初的认知对于直接映射区的线性地址是正确的:直接映射区的内核虚拟地址减去page_offset_base就能得到物理地址,但这个结论只适用于%lx打印的真实虚拟地址。

而你用__GFP_HIGHMEM申请的buf_high属于高端内存,这类内存并不在直接映射区里,所以不能用这个方法转换物理地址,需要用kmap()临时映射后才能访问,这部分地址本身就不满足直接映射的规则。

内容的提问来源于stack exchange,提问作者Haoan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 10:33:59