Linux内核编译时生成IOMEM虚拟地址的疑问及KASLR影响
问题描述
我正在编写一个向内存映射寄存器写入数据的FIQ handler,当前面临的问题是需要获取该寄存器物理地址对应的虚拟地址(因为FIQ模式下无法直接写入物理地址,与普通模式一致)。
我在查阅内核源码参考实现时,发现了这段汇编代码:
omap_ih1_base: .word OMAP1_IO_ADDRESS(OMAP_IH1_BASE) deferred_fiq_ih_base: .word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE) omap1510_gpio_base: .word OMAP1_IO_ADDRESS(OMAP1510_GPIO_BASE) qwerty_fiqin_end:
对应的宏定义如下:
#define OMAP1_IO_OFFSET 0x00f00000 /* Virtual IO = 0xff0b0000 */ #define OMAP1_IO_ADDRESS(pa) IOMEM((pa) - OMAP1_IO_OFFSET)
该实现正好符合我的需求,但我有两个疑问:
- 他们如何在编译时生成虚拟地址?
- 若开启KASLR(地址空间随机化),该机制是否会失效?
解答
1. 编译时生成虚拟地址的原理
OMAP1这类早期ARM平台采用固定IO地址映射,内核在编译阶段就把物理IO地址和虚拟地址的映射关系硬编码好了。
具体流程是:
- 内核预先为IO区域分配了固定的虚拟地址范围(比如注释里提到的
0xff0b0000) OMAP1_IO_OFFSET是物理地址与对应虚拟地址的固定差值,通过物理地址 - 偏移量的计算就能直接得到虚拟地址- 宏
OMAP1_IO_ADDRESS在编译时会被预处理器展开并完成数值计算,最终把结果作为立即数写入汇编的.word指令中——生成的二进制文件里直接存储了计算好的虚拟地址,完全不需要运行时动态解析。
这种方案能成立,核心是依赖平台IO空间映射关系的固定性。
2. KASLR对该机制的影响
会直接失效,原因很明确:
- KASLR的核心作用就是在系统启动时随机化内核镜像(包括IO映射区域)的虚拟地址,彻底打破了编译阶段的固定映射关系
- 原来的
OMAP1_IO_OFFSET是固定差值,编译时算出的虚拟地址在开启KASLR后,已经不再对应实际运行时的IO虚拟地址空间 - 这类依赖编译时硬编码虚拟地址的FIQ handler,在KASLR开启后会访问错误的内存地址,直接导致功能异常甚至系统崩溃。
如果要适配KASLR,必须改用运行时动态获取虚拟地址的方案:比如在FIQ handler初始化阶段,从内核页表中查询目标物理地址对应的虚拟地址,再把这个地址写入handler的变量中,而不是在编译时硬编码死。
内容的提问来源于stack exchange,提问作者InsaneCoder
相关产品推荐
相关产品推荐

