Я программирую микроконтроллеры, такие как STM32F4 ** и STM32F0 **, используя компилятор ARM GCC noneabi, c / c ++ и нашел интересный паттерн.
Если я создаю какой-нибудь файл * .bin, его размер всегда делится на 4.
Я думаю, что это может быть потому, что MCU является 32-битным (= 4 байта). Поэтому bin_size% 4 == 0. Я попробовал несколько «хаков»; например, увеличить некоторый байтовый массив на 1, но двоичный размер всегда одинаков. Когда я увеличиваю массив, размер двоичного файла увеличивается, но он снова делится на 4.
Могу ли я считать этот эффект аксиомой?
Или есть какая-то ситуация, когда это не работает? Например, возможно ли как-то переключить 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 -nostdlib
, чтобы пропустить все стандартные вещи библиотеки. Результат
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, такие как серии STM32, используют набор команд Thumb2, представляющий собой комбинацию 16- и 32-битных инструкций. Оказывается, наша первая программа имела длину, кратную четырем. Я добавил один 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 в 16-битный режим»
Там является режим 16 бит, но вы не можете точно понять, что это означает. Чтобы гуглить, вы должны искать «ARM Thumb». Это вполне может привести к * bin-файлам, кратным 2 байтам.
Однако «32-битный режим» и «16-битный режим» обычно относятся к размерам указателей или регистров, а не к размерам команд, например, набор инструкций AMD x64 может называться «режимом 64 битов», даже если его инструкции имеют переменную длину. Некоторые инструкции x64 занимают всего один байт.