GAS(gcc/as)自动生成未声明的.text/.data/.bss段问题排查
问题原因
两个问题的根源都是GAS和NASM的默认行为差异:
- 多余的空
.text/.data/.bss段:通过GCC驱动调用GAS汇编.S文件时,汇编器会默认生成这三个标准段的标记,哪怕源码中完全没有写入任何内容,也会保留大小为0的空段,这和NASM仅生成显式声明段的逻辑不同。这些空段仅存在于目标文件中,不会被链接到最终内核(除非显式在链接脚本中引用),本身不影响功能。 - 段属性缺失、地址重叠:使用
.section指令声明自定义段时,没有手动指定段标志。GAS对未指定标志的自定义段,默认不会添加ALLOC/LOAD属性,导致链接器认为.multiboot_header段不需要加载到内存,最终生成的.boot段没有分配有效地址空间,后续的.text段直接被排布到和.boot相同的起始地址,出现重叠。对比贴出的两个readelf结果就能验证:GAS版本的.boot段Flags列为空,没有A(alloc)标记,而正常工作的NASM版本.boot段是带A标记的。
解决方法
只需要修改multiboot_header.S中的段声明,手动给自定义段加上正确的属性即可,多余空段不需要额外处理(大小为0不影响结果):
- 把原文件第一行的段声明:
.section .multiboot_header
替换为:
.section .multiboot_header, "a", @progbits
参数说明:
"a":即alloc属性,标记该段需要被加载到内存,补上之前缺失的ALLOC、LOAD标志@progbits:标记该段存储实际的程序数据,不是无内容的空段
- 修改后重新汇编、链接,会得到符合预期的结果:
- 目标文件中的
.multiboot_header段会和NASM产物一致,带上CONTENTS, ALLOC, LOAD, READONLY, DATA属性 - 最终内核的
.boot段会正确带上A标志,.text段会自动排布在.boot段之后,不再出现地址重叠问题,效果和NASM编译版本完全一致。
补充说明:如果确实想消除目标文件里的空标准段,可以在汇编时给gcc加
-fno-builtin -ffreestanding参数,不过这步不是必须的,不影响最终内核的运行效果。
内容的提问来源于stack exchange,提问作者SamFF
相关产品推荐
相关产品推荐

