Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Распределение оперативной памяти в STM32

Чт авг 23, 2018 11:05:04

Тут идут исторические размышления на тему...
СпойлерКогда появился язык Си, распределение памяти для него сделали стандартным для PDP-11, где он впервые появился. А именно, с начала памяти, сразу после области векторов, располагался стек, за ним программа, а после программы - куча, и все остальное. Расположить стек в конце памяти было нельзя - там была операционка, которая, к тому же могла подгружать свои части туда же, т.е. верхний свободный адрес был нестационарным. Для программирования на Си это было весьма неудобно - приходилось разбираться, какого размера нужен стек каждой из программ и указывать нужные ключи линкеру.

Потом пришли времена MS-DOS и эта проблема ушла: в начале памяти операционка, за ней сама программа, далее вся память свободна, с ее начала располагают кучу, в конце - стек, и вперед, пока стек с кучей не столкнутся. (Я уж не говорю про винды, в которых для обозримых задач память можно считать бесконечной).

Да и на МК - на тех же AVR - стек кладут в конец ОП, кучу - в начало. А вот на хрена для АРМов сделали такую глупость, как стек в начале памяти? Чтобы добавить юзерам геморрою? Посчитай, мол, еще и стек...
Я правильно понимаю, что локальные для функции переменные и массивы располагаются в области стека? А статические и глобальные (в смысле, определенные вне функций и видимые во всех функциях) - перед кучей, да? Ну, и malloc() выдаст память из кучи, да?

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 11:13:07

afz писал(а):Я правильно понимаю, что локальные для функции переменные и массивы располагаются в области стека?
Как правило да.

afz писал(а):А статические и глобальные (в смысле, определенные вне функций и видимые во всех функциях) - перед кучей
Необязательно. Распределением что и где (если явно не заданно) занимается компилятор/линкер.

afz писал(а):А вот на хрена для АРМов сделали такую глупость, как стек в начале памяти?
Вначале таблицы векторов находится указатель на стек, а он обычно располагается в конце памяти.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 13:16:55

Из файла startup_stm32f10x_md.c
Код:
#define STACK_SIZE       0x00000100      /*!< The Stack size suggest using even number     */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];

Т.е. в секции .co_stack размещен массив размером STACK_SIZE - это и есть зарезервированная области для стека. Линковщик секцию .co_stack расположит последней среди всех секций ОЗУ.

В таблице векторов такая запись
Код:
  (void *)&pulStack[STACK_SIZE],     /*!< The initial stack pointer         */
  Reset_Handler,                /*!< Reset Handler                            */
  NMI_Handler,
...
... 

Т.е. указатель стека инициализируется адресом расположения последнего элемента массива pulStack. Если хочется однозначно указать на конец памяти, то можно строку (void *)&pulStack[STACK_SIZE], заменить например на (void*)(0x2000xxxx) . Ну или вставку ассемблерную вставить изменяющую указатель стека. Однако лучше изменять только STACK_SIZE, тогда ты точно знаешь сколько у тебя выделено памяти на стек.

Это для компилятора GCC, у других как там я не знаю.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 14:29:43

Это для компилятора GCC, у других как там я не знаю.
Да в принципе у всех примерно одинаково. Хочу лишь уточнить, что скриптом линкера стэк можно хоть на кукушку, хоть за можай загнать.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 19:48:58

Z_h_e писал(а):Это для компилятора GCC, у других как там я не знаю.
У Кейла то же самое, не считая того, что стартап у него на асме.То есть, все обследованные системы программирования в начале SRAM располагают статические переменные, затем кучу заданного размера и стек, тоже заданного размера. Да, я уточнил, Кейл по malloc() выдает память из кучи, думаю, остальные делают то же самое.

Получается, что остальная оперативка просто недоступна. Спрашивается, зачем? Ведь линкер собирает программу для конкретного камня, размер его памяти заведомо известен. Кто мешал стек разместить в физическом конце оперативки и не фиксировать соотношений между стеком и кучей - пусть растут навстречу друг другу, пока не встретятся. Так нет, нас заставляют рулить еще двумя параметрами, причем их дефолтные размеры поставлены просто смешными. На чем часто обламываются начинающие.

В общем, непонятно, зачем так сделали...

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 20:00:41

afz писал(а):В общем, непонятно, зачем так сделали...
Я думаю в скрипте линковщика можно жестко указать, где должен находится сегмент стэка. И тогда можно будет более корректно установить указатель стека в конец памяти.

Добавлено after 4 minutes 4 seconds:
afz писал(а):Получается, что остальная оперативка просто недоступна.
ЯВУ как бы избавляет программера думать об распределении памяти. Добавил переменныю - все "само" сдвинулось. Добавил много - наругается. Так что вся доступна, только надо заявить сколько тебе надо.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 20:06:23

afz писал(а):Кто мешал стек разместить в физическом конце оперативки и не фиксировать соотношений между стеком и кучей - пусть растут навстречу друг другу, пока не встретятся.
Стек может быть в конце оперативки.
СпойлерИзображение
Stack.png
(19.18 KiB) Скачиваний: 180
Адрес 0x20005000 это конец оперативки у STM32F103C8T6. Компилятор GCC. Скрипт линкера стандартный из IDE.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 20:12:44

Получается, что остальная оперативка просто недоступна. Спрашивается, зачем? Ведь линкер собирает программу для конкретного камня, размер его памяти заведомо известен.
Линкер выделяет программе ровно столько памяти сколько ей нужно. Зачем давать программе больше чем ей нужно? Она от этого лучше работать не будет.

Кто мешал стек разместить в физическом конце оперативки и не фиксировать соотношений между стеком и кучей - пусть растут навстречу друг другу, пока не встретятся.
Кто запрещает вам это сделать? Скрипт линкера и стартап доступны для редактирования - пишите как считаете нужным. От себя лишь пожелаю, чтобы они всё же не встречались у вас.

Так нет, нас заставляют рулить еще двумя параметрами, причем их дефолтные размеры поставлены просто смешными.
Нормальные размеры, просто использовать их надо с головой.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 20:30:24

Мурик писал(а):Адрес 0x20005000 это конец оперативки у STM32F103C8T6. Компилятор GCC. Скрипт линкера стандартный из IDE.
А вот у меня пример небольшой прожки со стандартным линкером на тот же камень.
СпойлерИзображение


Добавлено after 7 minutes 4 seconds:
Мурик писал(а):Адрес 0x20005000 это конец оперативки у STM32F103C8T6.
Хммм. Размер то ОЗУ до 0x20004FFF. Разве не должен быть максимальный адрес для 32битного регистра быть 0x20004FFC для такого размера памяти?

Добавлено after 4 minutes 50 seconds:
Хотя, видимо укзатель сначала уменьшается и потом запись, а увеличивается уже после чтения.
Вложения
vvth.png
(9.64 KiB) Скачиваний: 865

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 20:56:46

А у Кейла все оказалось гоораздо хуже! Автоматические (локальные) переменные Кейл располагает после стека.

Z_h_e писал(а):ЯВУ как бы избавляет программера думать об распределении памяти. Добавил переменныю - все "само" сдвинулось. Добавил много - наругается. Так что вся доступна, только надо заявить сколько тебе надо.
VladislavS писал(а):Линкер выделяет программе ровно столько памяти сколько ей нужно. Зачем давать программе больше чем ей нужно? Она от этого лучше работать не будет.

Не всегда. Я часто пользовал выделение буферов и пр. динамических областей по malloc(), разбирался, сколько там можно взять памяти и действовал должным образом, в зависимости от количества памяти.

VladislavS писал(а):Кто запрещает вам это сделать? Скрипт линкера и стартап доступны для редактирования - пишите как считаете нужным. От себя лишь пожелаю, чтобы они всё же не встречались у вас.
С Кейлом - не выйдет.

Добавлено after 5 minutes 12 seconds:
Z_h_e писал(а):Хотя, видимо укзатель сначала уменьшается и потом запись, а увеличивается уже после чтения.

Единственная архитектура, у которой в стек пишется по *SP-- - это AVR. У всех прочих запись в стек идет по *--SP, т.е., если стек пуст, его указатель должен указывать ЗА последний байт области стека.

Добавлено after 9 minutes 27 seconds:
Мурик писал(а):
afz писал(а):Я правильно понимаю, что локальные для функции переменные и массивы располагаются в области стека?
Как правило да.
Увы, у Кейла это не так!
Последний раз редактировалось afz Чт авг 23, 2018 21:24:21, всего редактировалось 1 раз.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 21:02:23

Автоматические (локальные) переменные Кейл располагает после стека.
Вы что-то конкретно путаете! Линкер размещает в памяти глобальные и статические локальные данные. Всё локальное в стеке и регистрах. А динамическое в куче. Это табу.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 21:16:21

Мурик писал(а):Адрес 0x20005000 это конец оперативки у STM32F103C8T6. Компилятор GCC. Скрипт линкера стандартный из IDE.
А вот у меня пример небольшой прожки со стандартным линкером на тот же камень.
СпойлерИзображение
Зависит от IDE. В EmBitz вначале располагаются переменные, после куча и в конце ОЗУ находится стек. Из map файла.
Спойлер
Код:
.data           0x20000000       0x68 load address 0x08000570
                0x20000000                __data_start__ = .
 *(vtable)
 *(.data*)
 .data.impure_data
                0x20000000       0x60 ./embitz/1.11/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/lib/armv7-m\libg_n.a(lib_a-impure.o)
                0x20000060                . = ALIGN (0x4)
                0x20000060                PROVIDE (__preinit_array_start, .)
 *(.preinit_array)
                0x20000060                PROVIDE (__preinit_array_end, .)
                0x20000060                . = ALIGN (0x4)
                0x20000060                PROVIDE (__init_array_start, .)
 *(SORT(.init_array.*))
 *(.init_array)
 .init_array    0x20000060        0x4 ./embitz/1.11/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/5.4.1/armv7-m/crtbegin.o
                0x20000064                PROVIDE (__init_array_end, .)
                0x20000064                . = ALIGN (0x4)
                [!provide]                PROVIDE (__fini_array_start, .)
 *(SORT(.fini_array.*))
 *(.fini_array)
 .fini_array    0x20000064        0x4 ./embitz/1.11/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/5.4.1/armv7-m/crtbegin.o
                [!provide]                PROVIDE (__fini_array_end, .)
                0x20000068                . = ALIGN (0x4)
                0x20000068                __data_end__ = .

.jcr            0x20000068        0x0 load address 0x080005d8
 .jcr           0x20000068        0x0 ./embitz/1.11/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/5.4.1/armv7-m/crtbegin.o

.igot.plt       0x20000068        0x0 load address 0x080005d8
 .igot.plt      0x20000068        0x0 ./embitz/1.11/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/5.4.1/armv7-m/crtbegin.o

.bss            0x20000068       0x1c load address 0x080005d8
                0x20000068                __bss_start__ = .
 *(.bss*)
 .bss           0x20000068       0x1c ./embitz/1.11/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/5.4.1/armv7-m/crtbegin.o
 *(COMMON)
                0x20000084                __bss_end__ = .

.heap           0x20000088        0x0
                0x20000088                __end__ = .
                0x20000088                end = __end__
 *(.heap*)
 .heap          0x20000088        0x0 obj\release\src\startup_stm32f10x_md.o
                0x20000088                __HeapLimit = .

.stack_dummy    0x20000088      0x100
 *(.stack)
 .stack         0x20000088      0x100 obj\release\src\startup_stm32f10x_md.o
                0x20005000                __StackTop = (ORIGIN (RAM) + LENGTH (RAM))
                0x20004f00                __StackLimit = (__StackTop - SIZEOF (.stack_dummy))
                0x20005000                PROVIDE (__stack, __StackTop)
Но это больше зависит не от IDE, а от скрипта линкера. По умолчанию в EmBitz от так распределяет данные в ОЗУ и на мой взгляд довольно оптимально.

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 21:22:47

VladislavS писал(а):Вы что-то конкретно путаете!

Блин, точно! Посыпаю голову пеплом. Виноват. Тогда действительно стоит разобраться, и что-то подкрутить Кейлу. Вопрос только что именно?

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 21:29:15

Вопрос только что именно?
Cтартап и скрипт линкера (scatter file в терминологии Keil).

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 21:33:19

Это каждому проекту крутить, а хотелось бы поставить где-нибудь галочку, чтобы он делал это сам и для всех. Ну, в крайнем случае, ставить эту галочку каждому проекту...

Re: Распределение оперативной памяти в STM32

Чт авг 23, 2018 21:39:16

И кнопку "make happy".

Re: Распределение оперативной памяти в STM32

Пт авг 24, 2018 06:27:30

Нет, одной мало. Дайте две! :)))

И вообще, что за фигня? EmBitz же так делает, почему бы и Кейлу так не делать? Попробовать, что-ли, EmBitz?

Добавлено after 2 minutes 48 seconds:
Да, кстати, а где прописан прототип malloc() ? В "больших" системах я всегда писал #include <malloc.h>, а здесь (по крайней мере, у Кейла) такого файла нет...

Re: Распределение оперативной памяти в STM32

Пт авг 24, 2018 07:25:11

И вообще, что за фигня? EmBitz же так делает, почему бы и Кейлу так не делать?
Вы что-то путаете. Keil делает ровно то что написано в вашем проекте. Куда поместите стек, там он и будет. Не делайте проблему там где её нет. У Кеил настоящих косяков полно, а вы ему ещё несуществующие приписываете.

Да, кстати, а где прописан прототип malloc() ? В "больших" системах я всегда писал #include <malloc.h>, а здесь (по крайней мере, у Кейла) такого файла нет...
Всегда он в stdlib.h был.

Re: Распределение оперативной памяти в STM32

Пт авг 24, 2018 07:57:34

Keil делает ровно то что написано в вашем проекте. Куда поместите стек, там он и будет.
Угу. Только EmBitz делает это сам, без моих движений, а Кейлу я должен буду править каждый проект, где мне нужно такое распределение памяти. И еще непонятно, как при этом бороться с кейловскими Stack_Size и Heap_Size - их же тоже придется регулярно править...

Re: Распределение оперативной памяти в STM32

Пт авг 24, 2018 11:00:38

У меня сложилось впечатление, что ни одного живого проекта ни в одной среде вы не сделали. Зато поговорить всегда пожалуйста. В любой среде программист должен держать под контролем распределение памяти. Если вы этого не хотите делать, то когда-нибудь всё равно огребёте.
Ответить