Как я могу выровнять стек к концу SRAM?
У меня есть STM32F103VCT6
микроконтроллер с 48kb SRAM, и недавно у меня произошел конфликт памяти:
У меня есть статическая переменная (давайте назовем ее A
) находится в куче с размером 0x7000
и я написал несколько простых функций для получения информации о стеке и куче:
void check(int depth) {
char c;
char *ptr = malloc(1);
printf("stack at %p, heap at %p\n", &c, ptr);
if (depth <= 0) return;
check(depth-1);
}
Итак, я получил что-то вроде этого:
stack at 2000939b, heap at 20008fd0
stack at 20009383, heap at 20008fe0
stack at 2000936b, heap at 20008ff0
stack at 20009353, heap at 20009000
stack at 2000933b, heap at 20009010
stack at 20009323, heap at 20009020
stack at 2000930b, heap at 20009030
stack at 200092f3, heap at 20009040
stack at 200092db, heap at 20009050
stack at 200092c3, heap at 20009060
stack at 200092ab, heap at 20009070
Все статические переменные (включая A
) уже получил свою кучу, поэтому куча находится на 0x8fd0
, И кажется, что изначально указатель стека находится в 0x939b
это далеко от 48кб (0xc000
)
И когда я изменил A
переменный размер до 0x4000
У меня есть эта картина:
stack at 2000639b, heap at 20005fd0
stack at 20006383, heap at 20005fe0
stack at 2000636b, heap at 20005ff0
stack at 20006353, heap at 20006000
stack at 2000633b, heap at 20006010
stack at 20006323, heap at 20006020
stack at 2000630b, heap at 20006030
stack at 200062f3, heap at 20006040
stack at 200062db, heap at 20006050
stack at 200062c3, heap at 20006060
stack at 200062ab, heap at 20006070
Таким образом, похоже, что расположение стека не находится в конце SRAM, но, как-то, зависит от пользовательских переменных.
Как я могу выровнять стек так, чтобы он находился в самом конце SRAM (на 48 КБ)?
Я использую CooCox IDE с GNU Tools ARM Embedded
Набор инструментов.
Спасибо!
РЕДАКТИРОВАТЬ:
Извините за недоразумение, A
не является константой, я назвал это статическим только из-за ключевого слова:
static uint8_t A[A_SIZE];
printf("A is at %p\n", &A);
Это показывает, что A
находится в начале памяти:
A is at 20000c08
2 ответа
Я нашел причину: это потому, что размер стека на самом деле фиксирован, и он находится в куче (если бы я мог назвать это кучей).
В файле startup_stm32f10x*.c
есть раздел:
/*----------Stack Configuration----------*/
#define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */
И тогда очень следующая строка:
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];
Я изменил это значение на 0x00000500
и получил все работает.
В цепочке инструментов GNU используется целевой скрипт компоновщика (обычно с расширением имени файла.ld). Это будет описывать макет памяти вашей цели и может быть настроен в соответствии с вашими потребностями.
Способ, которым вы вывели стек и расположение кучи, несколько недетерминирован и слишком сложен. Гораздо проще и совершенно точно просто посмотреть на вывод файла карты, сгенерированный компоновщиком (опция командной строки ld -Map <mapfile>
).
Куча по определению для динамического размещения, поэтому неявно не использовать для выделения статических данных; это заблуждение с вашей стороны. Компоновщик будет распределять статические данные во время сборки. Сценарий компоновщика, вероятно, затем выделит стек фиксированного размера, а затем выделит все, что осталось и не зарезервировано для других целей в куче. Настраиваемый сценарий может также выделять области для других целей, таких как, например, буферы DMA или домены с резервным питанием.
В любом случае размещение стека вряд ли будет решением вашей реальной проблемы; это просто движет вещами; это не увеличит доступную память; любое переполнение стека просто столкнется с чем-то другим.