ld如何决定节对齐?Cortex-M平台.bss 2KB对齐异常排查
Cortex-M交叉编译中.bss段2KB对齐的原因及解决方法
问题现象
使用arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi为Cortex-M微控制器交叉编译后,通过objdump和readelf查看可执行文件,发现.bss段的对齐要求为2KB(2048字节):
objdump输出
Idx Name Size VMA LMA File off Algn Flags [...] 6 .data 0000354c 20001000 3008f614 00091000 2**3 CONTENTS, ALLOC, LOAD, DATA 7 .dataNonCacheable 00000000 20000d00 20000d00 00094550 2**3 CONTENTS 8 .data_OCRAM 00000000 20200000 20200000 00094550 2**0 CONTENTS 9 .bss 00033d3c 20004800 20004800 00000800 2**11 ALLOC 10 .bssNonCacheable 00000d00 20000000 20000000 00001000 2**6 ALLOC 11 .bss_OCRAM 00029558 20200000 20200000 00001000 2**3 ALLOC [...]
readelf输出
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [...] [ 7] .data PROGBITS 20001000 091000 00354c 00 WA 0 0 8 [ 8] .dataNonCacheable PROGBITS 20000d00 094550 000000 00 W 0 0 8 [ 9] .data_OCRAM PROGBITS 20200000 094550 000000 00 W 0 0 1 [10] .bss NOBITS 20004800 000800 033d3c 00 WA 0 0 2048 [11] .bssNonCacheable NOBITS 20000000 001000 000d00 00 WA 0 0 64 [12] .bss_OCRAM NOBITS 20200000 001000 029558 00 WA 0 0 8 [13] .textFlash PROGBITS 30002348 003348 0627c8 00 AX 0 0 8 [...]
但链接脚本中仅设置了.bss段8字节对齐:
.bss : ALIGN(8) { *(.bss*) *(COMMON) . = ALIGN(4) ; } > SRAM_DTC
排查过程
最初怀疑是编译器默认设置了2KB最小对齐,于是用以下命令检查所有目标文件的.bss段对齐:
for f in `find FW/build/ -type f -name *.o` ;do echo $f; /opt/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-readelf -S -W $f; done | grep " .bss " | awk '{ if ($NF > 1) print $0 }'
结果未发现任何.o文件的.bss段对齐大于1,因此推测是链接器自行提升了对齐级别。
根因定位(2024-08-30更新)
修改排查命令后:
for f in `find FW/build/ -type f -name *.o` do echo $f /opt/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-readelf -S -W $f done | grep " .bss" | \ awk 'strtonum($6) > 0 {print $NF, $0}' | \ sort -n | \ cut -d' ' -f2-
最终找到导致对齐提升的变量:
[...] [172] .bss.txFrameInfoArray_1.0 NOBITS 00000000 0012c0 000048 00 WA 0 0 64 [173] .bss.txDataBuff_1.1 NOBITS 00000000 0012c0 001200 00 WA 0 0 64 [176] .bss.txFrameInfoArray_0.4 NOBITS 00000000 0012c0 000048 00 WA 0 0 64 [177] .bss.txDataBuff_0.5 NOBITS 00000000 0012c0 001200 00 WA 0 0 64 [121] .bss._dcd_data NOBITS 00000000 001800 000600 00 WA 0 0 2048
链接器的核心规则是:段的对齐级别会自动提升到段内所有元素的最高对齐要求。这里_dcd_data变量被设置为2048字节(2KB)对齐,因此整个.bss段的对齐级别被强制提升到2KB,覆盖了链接脚本中设置的8字节对齐。
解决方法
针对这个问题,有三种可行的解决思路:
- 调整变量的对齐要求
如果_dcd_data不需要2KB这么严格的对齐,可以修改其对齐属性。比如将原来的2KB对齐改为8字节对齐:
__attribute__((aligned(8))) uint8_t _dcd_data[0x600];
- 在链接脚本中单独处理该变量
将_dcd_data放到独立的段中,单独设置对齐要求,避免影响整个.bss段:
.bss : ALIGN(8) { *(.bss*) /* 排除_dcd_data所在的子段 */ *(!.bss._dcd_data) *(COMMON) . = ALIGN(4); } > SRAM_DTC /* 单独存放_dcd_data,设置2KB对齐 */ .bss_dcd : ALIGN(2048) { *(.bss._dcd_data) } > SRAM_DTC
- 接受当前对齐并显式声明
如果确实需要_dcd_data保持2KB对齐,且不介意整个.bss段的对齐级别,可以保留现状,或者在链接脚本中显式设置.bss段的对齐为2048,避免后续混淆:
.bss : ALIGN(2048) { *(.bss*) *(COMMON) . = ALIGN(4); } > SRAM_DTC
内容的提问来源于stack exchange,提问作者mastupristi
相关产品推荐
相关产品推荐

