stm32 编译出的bin文件一定是4字节的倍数吗?

发布时间 2023-05-25 09:54:34作者: 天街小雨润地狠

最近在研究固件升级,在烧写内部FLASH时突然产生一个问题编译出的bin文件一定是4字节的倍数吗?如果不是那么以bin文件总长度除以4的方式写入flash就有可能舍掉了最后的余数。

在stack overflow上得到的答案是:正常情况下编译产生的bin文件是4的倍数,但是并不一定是4字节的倍数,4字节对齐只是因为方便,实际取决于连接脚本等文件的设置。

如果我们打开连接脚本文件(.ld)的话,会看到很多声明如下所示

. = ALIGN(4);
它们指示链接器将当前输出地址提升到可被4整除的值。

举例如下,如果我创建一个空工程,删除以下连接脚本中的align语句

 1 ENTRY(Reset_Handler)
 2 __stack = 0x20014000;
 3 MEMORY
 4 {
 5 FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 512K
 6 RAM   (xrw)     : ORIGIN = 0x20000000, LENGTH = 80K
 7 }
 8 SECTIONS
 9 {
10   .isr_vector :
11   {
12     . = ALIGN(4);
13     KEEP(*(.isr_vector))
14     . = ALIGN(4);
15   } >FLASH
16   .text :
17   {
18     *(.text)
19     *(.text*)
20   } >FLASH
21   .rodata :
22   {
23     *(.rodata)
24     *(.rodata*)
25   } >FLASH
26   _sidata = LOADADDR(.data);
27   .data : 
28   {
29     _sdata = .;
30     *(.data)
31     *(.data*)
32     _edata = .;
33   } >RAM AT> FLASH
34   .bss :
35   {
36     _sbss = .;
37     *(.bss)
38     *(.bss*)
39     *(COMMON)
40     _ebss = .;
41   } >RAM
42 }

以上连接脚本源程序如下:

void Reset_Handler(void) {
    while(1)
        ;
}

用-nostartfiles -nodefaultlibs -nostdlib编译连接这个程序,把标准库相关的文件都删除掉,最后得出的结果如下:

arm-none-eabi-size --format=berkeley "unaligned.elf"
   text    data     bss     dec     hex filename
    320       0       0     320     140 unaligned.elf

可以被4整除,然后我在代码中加入一个char型的变量,如下所示:

1 volatile char c = 0x42;
2 void Reset_Handler(void) {
3     while(1)
4         c+=1;
5 }

重新编译连接得到结果是:

Invoking: Cross ARM GNU Print Size
arm-none-eabi-size --format=berkeley "unaligned.elf"
   text    data     bss     dec     hex filename
    336       1       0     337     151 unaligned.elf
Finished building: unaligned.siz

文件大小不在对4字节对齐。

进一步说明指令是按照16位对齐的。

以Cortex-M作为内核的MCU 如STM32系列使用Thumb2指令集,指令集中的指令有16位也有32位。这导致第一个程序最后是4字节的倍数。当我加入一个 nop指令后

1 void Reset_Handler(void) {
2     asm("nop");
3     while(1)
4         ;
5 }

编译结果比第一个程序大了两个字节,如下:

Invoking: Cross ARM GNU Print Size
arm-none-eabi-size --format=berkeley "unaligned.elf"
   text    data     bss     dec     hex filename
    322       0       0     322     142 unaligned.elf
Finished building: unaligned.siz

补充说明:

有人觉得可以把STM32 MCU切换的16位的模式就会得到16位对齐的bin文件。当你真的切换到16位模式确实很可能最后的出的bin文件是2字节的倍数了,但你可能不完全理解这意味着什么。“32位模式”和“16位模式”通常指指针或寄存器大小,而不是指令大小。例如,AMD x64指令集可能被称为“64位模式”,即使其指令长度可变。有些x64指令只有一个字节。