ARMv7a裸机系统静态分页:如何用符号生成页表项?
ARMv7a静态分页:自动关联顶级与二级页表的解决方案
问题分析
你遇到的报错invalid operands (.boot_data and *ABS* sections) for &,本质是GNU汇编器在单独汇编阶段无法处理未分配绝对地址符号的位运算——二级页表符号的绝对地址只有在最终链接时才能确定,汇编阶段仅能获取符号的相对偏移或未解析标记,无法完成& 0xfffffc00这类绝对地址位操作。
可行解决方案
方案1:通过链接器脚本生成顶级页表条目
这是最可靠的方式,直接利用链接器对全局符号绝对地址的计算能力,在链接阶段完成页表项的位运算和生成。
步骤1:编写链接器脚本(如linker.ld)
MEMORY { ROM : ORIGIN = 0x00000000, LENGTH = 1M ; 根据实际内存布局调整 } SECTIONS { .boot : { /* 定义顶级页表起始地址 */ top_level_table = .; /* 生成顶级页表条目:指向二级页表1 */ LONG((second_level_table_1 & 0xfffffc00) | 0x9) /* 添加其他顶级页表条目,格式同上 */ /* 确保顶级页表占满1KB(ARMv7a顶级页表固定1KB大小) */ . += (1024 - (. - top_level_table)); /* 二级页表1:自动对齐到1KB边界 */ . = ALIGN(1024); second_level_table_1 = .; *(.second_level_table_1) /* 确保二级页表占满1KB */ . += (1024 - (. - second_level_table_1)); /* 二级页表2:同理 */ . = ALIGN(1024); second_level_table_2 = .; *(.second_level_table_2) . += (1024 - (. - second_level_table_2)); } > ROM }
步骤2:编写汇编文件(如page_tables.S)
只需要定义二级页表的内容,顶级页表由链接器自动生成:
.section .second_level_table_1, "a" ; 二级页表1的条目示例:映射0x0地址的1MB区域为读写、非缓存 .rept 256 .word 0x00000000 + (. - second_level_table_1)*4096 | 0x12 .endr .section .second_level_table_2, "a" ; 二级页表2的条目示例:映射0x10000000地址的1MB区域 .rept 256 .word 0x10000000 + (. - second_level_table_2)*4096 | 0x12 .endr
方案2:汇编中结合链接器表达式(简化写法)
如果希望顶级页表定义在汇编文件中,可以通过链接器支持的表达式间接完成位运算,避免汇编阶段报错。
修改汇编文件中的顶级页表条目写法:
.section .boot_data, "a" .global top_level_table top_level_table: ; 利用链接器的移位运算屏蔽低10位,再或上配置位 .word ((second_level_table_1 >> 10) << 10) | 0x9 .word ((second_level_table_2 >> 10) << 10) | 0x9 ; 填充剩余顶级页表条目为0或其他配置 .space 1024 - (. - top_level_table), 0 .align 10 ; 强制二级页表按1KB对齐 .global second_level_table_1 second_level_table_1: .space 1024 ; 二级页表内容自行填充 .align 10 .global second_level_table_2 second_level_table_2: .space 1024
此时需要确保链接器支持对符号的移位运算(GNU ld完全支持),编译链接时指定链接器脚本以保证页表的正确布局。
关键说明
- ARMv7a的二级页表必须按1KB(0x400)对齐,所以需要用
.align 10或链接器的ALIGN(1024)确保布局正确。 - 链接器脚本的方式更易于维护,尤其是当页表数量增多时,无需手动跟踪地址变化。
内容的提问来源于stack exchange,提问作者George Hodgkins
相关产品推荐
相关产品推荐

