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

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字节对齐。

解决方法

针对这个问题,有三种可行的解决思路:

  1. 调整变量的对齐要求
    如果_dcd_data不需要2KB这么严格的对齐,可以修改其对齐属性。比如将原来的2KB对齐改为8字节对齐:
__attribute__((aligned(8))) uint8_t _dcd_data[0x600];
  1. 在链接脚本中单独处理该变量
    将_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
  1. 接受当前对齐并显式声明
    如果确实需要_dcd_data保持2KB对齐,且不介意整个.bss段的对齐级别,可以保留现状,或者在链接脚本中显式设置.bss段的对齐为2048,避免后续混淆:
.bss : ALIGN(2048)
{
    *(.bss*)
    *(COMMON)
    . = ALIGN(4);
} > SRAM_DTC

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 06:17:13