C++ ARM二进制大小

C++ ARM二进制大小,c++,binary,arm,stm32,bin,C++,Binary,Arm,Stm32,Bin,我正在使用ARM GCC noneabi编译器、c/c++编写MCU,如STM32F4**和STM32F0**,并发现了有趣的模式 如果我构建一些*.bin文件,它的大小总是可以被4整除 我想这可能是因为MCU是32位(=4字节)。因此,bin_大小%4==0。我尝试过一些“黑客”;例如,将某些字节数组放大1,但二进制大小始终相同。当我进一步放大数组时,二进制大小会更大,但也可以被4整除 我可以把这个效应看作公理吗?< /P> 或者在某些情况下,这不起作用?例如,是否可能以某种方式将32位STM

我正在使用ARM GCC noneabi编译器、c/c++编写MCU,如STM32F4**和STM32F0**,并发现了有趣的模式

如果我构建一些*.bin文件,它的大小总是可以被4整除

我想这可能是因为MCU是32位(=4字节)。因此,bin_大小%4==0。我尝试过一些“黑客”;例如,将某些字节数组放大1,但二进制大小始终相同。当我进一步放大数组时,二进制大小会更大,但也可以被4整除

我可以把这个效应看作公理吗?< /P>


或者在某些情况下,这不起作用?例如,是否可能以某种方式将32位STM32 MCU切换到16位模式?或者可以使用其他编译器创建不可被4整除的二进制文件?

可以创建任意大小的二进制文件,4字节对齐只是一个方便的问题。每个人都是这样做的,每个人都期待着

在链接器脚本文件中强制对齐。如果您查看项目的
*.ld
文件,您会发现有很多

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

因此,我创建了一个空项目,并从链接器脚本中删除了大部分
ALIGN
行:

ENTRY(Reset_Handler)
__stack = 0x20014000;
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 512K
RAM   (xrw)     : ORIGIN = 0x20000000, LENGTH = 80K
}
SECTIONS
{
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector))
    . = ALIGN(4);
  } >FLASH
  .text :
  {
    *(.text)
    *(.text*)
  } >FLASH
  .rodata :
  {
    *(.rodata)
    *(.rodata*)
  } >FLASH
  _sidata = LOADADDR(.data);
  .data : 
  {
    _sdata = .;
    *(.data)
    *(.data*)
    _edata = .;
  } >RAM AT> FLASH
  .bss :
  {
    _sbss = .;
    *(.bss)
    *(.bss*)
    *(COMMON)
    _ebss = .;
  } >RAM
}
最小程序:

void Reset_Handler(void) {
    while(1)
        ;
}
编译并将其与
-nostartfiles-nodefaultlibs-nostlib
链接,以省去所有标准库内容。结果是

arm-none-eabi-size --format=berkeley "unaligned.elf"
   text    data     bss     dec     hex filename
    320       0       0     320     140 unaligned.elf
可以被四整除的。然后我添加了一个char变量,并用它做了一些事情:

volatile char c = 0x42;
void Reset_Handler(void) {
    while(1)
        c+=1;
}
导致

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
指令与16位对齐。

基于Cortex-M的MCU(如STM32系列)使用Thumb2指令集,它是16位和32位指令的混合。事实证明,我们的第一个程序恰好有一个长度可以被4整除。我添加了一条
nop
指令

void Reset_Handler(void) {
    asm("nop");
    while(1)
        ;
}
与原始文件相比,文件大小增加了两个字节:

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
例如,是否可能以某种方式将32位STM32 MCU切换到16位模式

有一种16位模式,但您可能不完全理解这意味着什么。要用谷歌搜索它,你需要搜索“手臂拇指”。这很可能会导致*bin文件是2字节的倍数


然而,“32位模式”和“16位模式”通常指指针或寄存器大小,而不是指令大小。例如,AMD x64指令集可称为“64位模式”,即使其指令长度可变。有些x64指令只有一个字节。

你到底为什么希望二进制文件的大小不是4的倍数???你的目标是什么?编译器可能正在填充您的结构以确保干净的内存访问。如果你想打破这个,我不知道你希望达到什么。打开文件,在末尾添加一个字节,关闭它,你可以有一个奇数长度的文件,然后看看有多少工具在你尝试使用它时会打破…太好了,你的答案完全涵盖了我需要知道的所有问题!我已经打开了我的*.ld文件,并且有在每个部分对齐(4)。这可能就是为什么我的二进制文件大小总是可以被4整除的原因。我问这个问题是因为我有自己的引导加载程序,它能够将新的二进制文件闪存到MCU,我认为“可被4整除”规则是新的二进制文件必须通过的规则之一,还有CRC检查等等。现在我知道这并不容易。