LINUX.ORG.RU

А вот как определяют, сколько памяти доступно для sbrk/alloc?

 ,


0

1

Вот захочу я, допустим, реализовать функцию malloc на микроконтроллере (раньше, правда, никогда такой необходимости не нужно было, но если брать МК аж с 512К флеша и 64К ОЗУ?) И как мне узнать, сколько из этих 64К я могу честно откусить на что-нибудь вроде

mempage _pages[SIZE];
как узнать этот SIZE?

Понятно, что по memmap из даташита можно определить размер области данных, но как определить, сколько из этого объема займут всякие вспомогательные данные — глобальные переменные, адреса переходов и т.п.?

Извиняюсь за глупый вопрос, но интересно.

☆☆☆☆☆
Ответ на: комментарий от mix_mix

Ты прям КО. Откуда я вычислю 666?

А может я вообще ни байта не хочу потерять, хочу всю по максимуму использовать память?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от mix_mix

Я не хочу (да и не представляю, как это сделать) вручную считать, сколько у меня используется памяти.

Возможен такой вариант: скомпилять и по карте памяти посмотреть, затем соответствующие изменения внести, и перекомпилять. Но это как-то уж очень костыльно выходит...

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от mix_mix

Вот, скажем, в том же линуксе поступают "просто": резервируют первые дофига мегабайт памяти (кажись, на современных системах уже сотни!). А мне интересно, как сделать без нерационального использования ресурсов.

Eddy_Em ☆☆☆☆☆
() автор топика

как определить, сколько из этого объема займут всякие вспомогательные данные — глобальные переменные, адреса переходов и т.п.?

А откуда может взяться что-то, что не написано в том даташите и чего ты сам не написал? Или ты пишешь под какую-то ОС?

proud_anon ★★★★★
()
Ответ на: комментарий от Eddy_Em

Я не хочу (да и не представляю, как это сделать) вручную считать, сколько у меня используется памяти.

Если речь идёт о простом плоском бинарнике, поставить в конце него метку, взять её адрес и вычесть из неё адрес начала бинарника.

Disclaimer: я не программирую под микроконтроллеры. Имею опыт низкоуровневого программирования для x86.

proud_anon ★★★★★
()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от proud_anon

Я примерно об этом же и писал выше.

А вот интересно: не может ли препроцессор gcc сразу же этот адрес взять, да и вычислить?

Или двойная компиляция (первый раз компиляем только для получения map-файла, из него sed'ом выдираем нужный параметр, объявляем макрос и компиляем второй раз) — не такой уж и велосипед?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Вот так и появляются решения очень многих ЛОРовских тем.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от proud_anon

поставить в конце него метку, взять её адрес и вычесть из неё адрес начала бинарника

И он получит размер бинарника, но этот размер надо изначально (при компиляции) откуда-то взять, а формируется он с учётом размера _pages[], то есть мы вернулись к первому вопросу :3

mix_mix ★★★★★
()
Ответ на: комментарий от proud_anon

Да, блин, оно работает только для меток внутри функции. В этом есть определённая логика.

Тогда можно сделать следующее.

Размер бинарника можно определить после компиляции.

Адрес, куда поместится первый байт бинарника, если не в 0, должен быть известен.

Итак, можно начать бинарник так:

<Перейти на 8 байт вперёд><Размер бинарника - 8 байт><Код>

Тогда, учитывая, что размер инструкции процессора <Перейти на 8 байт вперёд> должен быть заранее известен, можно предсказать адрес, где будет лежать размер бинарника. А сам этот размер записывать туда после компиляции.

proud_anon ★★★★★
()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от proud_anon

Да проще все: gcc создает map-файл (если нужные флаги указать), из которого и берется реальная карта памяти. А второй компиляцией и двигаем соответствующим образом выделенное.

Просто думал, что можно за один проход сделать.

Eddy_Em ☆☆☆☆☆
() автор топика

распарсить исполняемый файл по секциям и посчитать размер конечных не константных данных(секции вроде .data) + учесть размер стека?

vova7890 ★★★
()
Ответ на: комментарий от Eddy_Em

А второй компиляцией и двигаем соответствующим образом выделенное.

А карта памяти после этого не изменится?

proud_anon ★★★★★
()
Ответ на: комментарий от vova7890

распарсить исполняемый файл по секциям

В исходной задаче ведь ничего не говорилось, что там есть загрузчик ELF или другого нетривиального формата.

proud_anon ★★★★★
()
Ответ на: комментарий от PolarFox

Вспоминаются всякие порноархитектуры вроде AVR, в которых код отдельно, а данные отдельно.

Если код отдельно, а данные отдельно, то, очевидно, для данных доступна вся память для данных.

proud_anon ★★★★★
()
Ответ на: комментарий от proud_anon

для данных доступна вся память для данных.

Кроме глобальных переменных и стека, что усложняет задачу изобретения malloc.

PolarFox ★★★★★
()
Последнее исправление: PolarFox (всего исправлений: 1)
Ответ на: комментарий от PolarFox

Кроме глобальных переменных и стека, что усложняет задачу изобретения malloc.

Это вот да, проблема... и как выкручиваются люди?

proud_anon ★★★★★
()
Ответ на: комментарий от proud_anon

Изменится, но общий-то объем мы заполним целиком!

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от PolarFox

freeRTOS использует malloc. Но там, кажись, сильно КПД использования памяти низкий.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Это всё умеет gcc. Я это делал, но давно, по этому забыл как. Но это точно можно сделать. :)

Могу поискать в старых залежах. Делал я как-то ОС с malloc-ом для микроконтроллера.

Puzan ★★★★★
()
Ответ на: комментарий от Eddy_Em

Вот что нашел.

Файл lpc2148_rom.ld:

ENTRY(_boot)
STACK_SIZE = 0x500;

/* Memory Definitions */
MEMORY
{
  ROM (rx) : ORIGIN = 0x00000000, LENGTH = 512k
  RAM (rw) : ORIGIN = 0x40000000, LENGTH = 32k
}

/* Section Definitions */
SECTIONS
{
  .text :
  {
    src/sys/crt0.o (.text)
    *(.text)
    *(.text.*)
    *(.glue_7)
    *(.glue_7t)
    *(.rodata)
    *(.rodata.*)
  } > ROM

  . = ALIGN(4);
  _etext = . ;

  .data : AT (_etext)
  {
    _data = .;
    *(.data)
  } > RAM
 
  . = ALIGN(4);
  _edata = . ;

  .bss (NOLOAD) :
  {
    __bss_start = . ;
    *(.bss)
    *(COMMON)
  } > RAM

  . = ALIGN(4);
  __bss_end = . ;

  .stack ALIGN(256) :
  {
    . += STACK_SIZE;
    PROVIDE (_stack = .);
  } > RAM

  _end = . ;
  PROVIDE (end = .);
}

А вот из файла mem_alloc.c:

/* Linker provided constant */
extern char end[];

...

heap_start = ((UINT32)end) & 0x00007FFF;

Puzan ★★★★★
()
Ответ на: комментарий от Puzan

Спасибо. Примерно ясно. В opencm3 есть объявление указателя _stack:

PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

Т.е. в принципе, действительно, если с форматом файла линковки разобраться, выходит, что можно все автоматизировать без необходимости многократного запуска gcc.

Eddy_Em ☆☆☆☆☆
() автор топика

Для контроллеров и процов у которых нет виртуализации памяти характерна такая особенность кучи как дефрагментация. Поэтому, даже если у вас свободно 4К, но где то по середине кучи выделен 1 байт, то 3К вы не получите, так как непрерывного пространства нет в кучи. Использование кучи в таких системах не безопасно. Используйте пулы памяти. Если требуется определить размер какой либо секции в памяти программ, то это отдельный разговор. Его можно вычислить из определений файла линковщика.

anper
()
Ответ на: комментарий от anper

Забыл указать - формат файла линковщика, естественно зависит от используемого компилятора. И соответственно подход будет немного отличаться.

anper
()
Ответ на: комментарий от Puzan

Не совсем правильный файл линковщика. Обычно делают так, что бы куча и стек «росли» на встречу друг другу. Т.е. стек в конце памяти, куча сразу с первого свободного байта ОЗУ.

anper
()
16 июня 2016 г.
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.