реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Coocox настройка heap?
maxntf
сообщение Apr 16 2016, 14:51
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



Не получается настроить кучу в coocox.
По тем пример что на форуме http://www.coocox.org/forum/viewtopic.php?f=2&t=917 у меня не получилось. Во первых потому, что они с ошибками, а во вторых там не указано куда именно в файле *.ld нужна сделать вставку.
В общем я сделал по другому:
1. В файле startup добавил
Код
/*----------Heap Configuration-----------------------------------------------*/
#define HEAP_SIZE       0x00001000
__attribute__ ((section(".heap")))
unsigned long pulHeap[HEAP_SIZE];

2. В файле ld перенес сектор .heap который там уже был, под сектор .co_stack
Код
    /* .stack_dummy section doesn't contains any symbols. It is only
    * used for linker to calculate size of stack sections, and assign
    * values to stack symbols later */
    .co_stack (NOLOAD):
    {
        . = ALIGN(8);
        *(.co_stack .co_stack.*)
    } > ram

    .heap (COPY):
    {
        __end__ = .;
        _end = __end__;
        end = __end__;
        *(.heap*)
        __HeapLimit = .;
    } > ram
    
    /* Set stack top to end of ram , and stack limit move down by
    * size of stack_dummy section */
    __StackTop = ORIGIN(ram ) + LENGTH(ram );
    __StackLimit = __StackTop - SIZEOF(.co_stack);
    PROVIDE(__stack = __StackTop);
    
    /* Check if data + heap + stack exceeds ram  limit */
    ASSERT(__StackLimit >= __HeapLimit, "region ram  overflowed with stack")


В файле syscalls.c вообще ничего не менял.
Вот map файл который получился, и как видно из скриншота, функция calloc возвращает указатель именно из области сектора .heap
Но только не пойму как работает ограничение, когда вылезаем за размеры кучи. Дело в том, что даже если я ставлю HEAP_SIZE 0x00000010. Программа работает но там явно память выделяется за границами кучи.

Сообщение отредактировал maxntf - Apr 16 2016, 15:02
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 16 2016, 15:40
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Сначала вот вам картинка распределения ОЗУ:
  • начало ОЗУ
  • переменные
  • переменные
  • переменные
  • сюда вы зачем-то засунули секцию co_stack
  • начало кучи
  • ↓куча растёт в сторону конца ОЗУ
  • ↓куча растёт в сторону конца ОЗУ
  • тут пусто
  • тут пусто
  • тут могут встретиться стек и ОЗУ
  • тут пусто
  • тут пусто
  • ↑сюда растёт стек
  • ↑сюда растёт стек
  • начало стека (конец ОЗУ)


Теперь пояснения.
секция co_stack, вероятно, фальшивая. То есть, для дела важен только её размер. Вкупе со значением HEAP_SIZE это позволяет линкеру выдать ошибку, если суммарный размер стек+куча+переменные превысит размер ОЗУ. То, что вы поместили эту секцию после секции text и перед секцией .heap, просто оставило неиспользуемый кусок ОЗУ между переменными и кучей.
Размер использованной кучи, скорее всего, не проверяется (можете посмотреть на функцию _sbrk() в syscalls.c. Максимум, что обычно делается - контролируется встреча кучи и стека. (И то далеко не всегда).


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
maxntf
сообщение Apr 16 2016, 18:06
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



Цитата(AHTOXA @ Apr 16 2016, 18:40) *
  • начало ОЗУ
  • переменные
  • переменные
  • переменные
  • сюда вы зачем-то засунули секцию co_stack
  • начало кучи
  • ↓куча растёт в сторону конца ОЗУ
  • ↓куча растёт в сторону конца ОЗУ
  • тут пусто
  • тут пусто
  • тут могут встретиться стек и куча
  • тут пусто
  • тут пусто
  • ↑сюда растёт стек
  • ↑сюда растёт стек
  • начало стека (конец ОЗУ)

Во первых, огромное спасибо за наглядную картинку - сразу много вещей стало понятно! Редко на форуме понимают тех кто только начинает осваивать новое.
Цитата(AHTOXA @ Apr 16 2016, 18:40) *
Размер использованной кучи, скорее всего, не проверяется (можете посмотреть на функцию _sbrk() в syscalls.c. Максимум, что обычно делается - контролируется встреча кучи и стека. (И то далеко не всегда).

Из вашего ответа, у меня напрашивается законный вопрос, почему на всех встречающихся примерах всегда указывается размер стека, и кучи?
Честно говоря я думал что стек и куча ограничиваются размером.

P.S.
Цитата(AHTOXA @ Apr 16 2016, 18:40) *
  • сюда вы зачем-то засунули секцию co_stack

Это coocox делает по умолчанию в new_project. и GCC предлагает свой ld с таким расположением.

Цитата(AHTOXA @ Apr 16 2016, 18:40) *
секция co_stack, вероятно, фальшивая.

Только вспомнил! По адресу 0х08000000 указан адрес 0х200055А8. То есть начало стека, так что получается что стек двигается с этого адреса в конец памяти?

Сообщение отредактировал maxntf - Apr 16 2016, 18:12
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 16 2016, 18:18
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(maxntf @ Apr 16 2016, 23:06) *
Из вашего ответа, у меня напрашивается законный вопрос, почему на всех встречающихся примерах всегда указывается размер стека, и кучи?

Ну, чтобы можно было проверить, что сумма стека и кучи поместится в ОЗУ.
Цитата(maxntf @ Apr 16 2016, 23:06) *
Это coocox делает по умолчанию в new_project. и GCC предлагает свой ld с таким расположением.

Я вот про это:
Цитата(maxntf @ Apr 16 2016, 19:51) *
2. В файле ld перенес сектор .heap который там уже был, под сектор .co_stack

Судя по всему, в исходном скрипте линкера было всё в соответствии с картой памяти, которую я нарисовал. А вы поменяли местами хип и стек.
Цитата(maxntf @ Apr 16 2016, 19:51) *
Только вспомнил! По адресу 0х08000000 указан адрес 0х200055А8. То есть начало стека, так что получается что стек двигается с этого адреса в конец памяти?

Стек двигается в начало памяти. Поэтому начало стека обычно устанавливают в самый конец памяти.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Lmx2315
сообщение Apr 16 2016, 18:40
Сообщение #5


отэц
*****

Группа: Свой
Сообщений: 1 729
Регистрация: 18-09-05
Из: Москва
Пользователь №: 8 684



Цитата(maxntf @ Apr 16 2016, 21:06) *
Во первых, огромное спасибо за наглядную картинку - сразу много вещей стало понятно!

sm.gif
Цитата
Только вспомнил! По адресу 0х08000000 указан адрес 0х200055А8. То есть начало стека, так что получается что стек двигается с этого адреса в конец памяти?

..главное похвалить, а саму схему можно не читать.


--------------------
b4edbc0f854dda469460aa1aa a5ba2bd36cbe9d4bc8f92179f 8f3fec5d9da7f0
SHA-256
Go to the top of the page
 
+Quote Post
maxntf
сообщение Apr 16 2016, 19:04
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



Цитата(Lmx2315 @ Apr 16 2016, 21:40) *
sm.gif
..главное похвалить, а саму схему можно не читать.

Да нет, схему я как раз понял. Только в стандартном варианте было примерно так, в понедельник точный map на работе посмотрю и покажу.
Код
.heap                                 0x200055a0     0x0
                                      0x200055a0               __end__ = .
                                      0x200055a0               _end = __end__
                                      0x200055a0               end = __end__
*(.heap*)
.co_stack
                                      0x200055a0     0x2000    ......
                                      0x200055a0               . = ALIGN (0x8)
*(.co_stack .co_stack*)
                                      0x200055a0     0x2000    ......
                                      0x200055a0               __HeapLimit = .
                                      0x20020000               __StackTop = .......
                                      0x2001e000               __StackLimit = .......

Я думал что co_stack это начало стека, и адрес кучи находится там же где и начало стека. По этому и начал пытаться перенести кучу. Точнее вообще понять где она расположена, и как задать ей размер.

P.S.
Я подключил библиотеку декодера speex, и при его инициализации у меня программа улетала в Default_Handler. Скорее всего из за того, что происходило прерывание, обработчик которого я не включил (наверное прерывание по переполнению стека). Программа улетала, когда выполнялась calloc 3-й раз. Я увеличил значение STACK_SIZE и все пошло. Получается что calloc выделяло память из адресного пространства стека (возвращало 0x200055a8), а адрес начала стека все таки 0x200055a0?
Или я все не так понял?

Сообщение отредактировал maxntf - Apr 16 2016, 19:24
Go to the top of the page
 
+Quote Post
maxntf
сообщение Apr 18 2016, 12:01
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



Вроде пришло понимание части вопросов! Что привело к возникновению еще большей "куче" вопросов.
Из того что понятно:
Прикрепленное изображение

- из этого понятно что верх стека по адресу 0x20000888 + 0x800(размер стека) = 0x20001088. Это значение записано и по адресу 0x08000000. За адресом 0x20001088 у нас больше ничего уже не будет хранится. то есть в данном случае я могу увеличить размер стека до значения 0x20020000 - 0x20000888(до этого адреса хранятся глобальные переменные).
Прикрепленное изображение

Теоретически куча может не то что встретится со стеком, а стереть его полностью, добравшись до точки В. То же самое может сделать и стек с кучей, если он доберется до точки А. Так?
Стек растет сегментами, в которых хранятся локальные переменные функции и адрес возврата. Чем больше локальных переменных в функции, тем больше сегмент стека. Если нужна локальная переменная большого размера, а точнее мы не знаем какого размера она будет, но знаем что может быть большой - лучше ей память выделить динамически из кучи то-есть области ближе к точке А. И при этом стек у нас вырастет не значительно.
Про ограничения стека и кучи (как я это понял)!
По факту мы не имеем каких то конкретных размеров стека и кучи. Размер стека от заданной его вершины и до начала локальных данных. Размер кучи с начала памяти локальных данных и до конца памяти.
Превышение лимита стека контролируется вылетом в прерывание HardFault (если такое происходит, значит полная же.. и нужно делать переорганизацию памяти, увеличивать стек или выбирать проц с большей памятью.
Превышение лимита кучи контролируется через некое ограничивающее значение, наверное __HeapLimit, если вообще контролируется это. На сколько я понял этот контроль настраивается в функции _sbrk, ее специально оставили пользователю. То есть там нужно сделать проверку, если пытаемся выделить память за пределами HeapLimit, тогда не выделять память.

А теперь собственно вопросы:
  • Это значение HeapLimit должно ведь быть динамическим. Ну типа до указателя стека, стек вырос и HeapLimit уменьшилось, стек уменьшился и HeapLimit увеличился? Иначе зачем тогда стек и кучу пихать в один сегмент памяти!
  • Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 18 2016, 12:13
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (maxntf @ Apr 18 2016, 15:01) *
[*] Это значение HeapLimit должно ведь быть динамическим.

Разумеется нет. Всегда есть явное или полуявное (типа вся свободная память) указание размера хипа. Менеджеры памяти никуда никакую память не растят, если запрошенное количество больше имеющейся. Явное указание есть тупейший вариант. С ним обычно для усугубления идет вариант, что все остальное стеку отдается - указывается минимально-отфонарное значение размера стека в рассчете на то, что свех этого будет еще какое то количество памяти нераспределенное линкером.
QUOTE
[*] Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу?

RTOS сама ничего и нигде не размещает. Размещает линкер я соответствии с указаниями данными Вами лично.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
maxntf
сообщение Apr 18 2016, 12:34
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



QUOTE (zltigo @ Apr 18 2016, 15:13) *
Разумеется нет.

Тогда мне не понятно, зачем делать, чтоб куча шла на встречу стеку? Почему не выделить вначале кусок памяти под стек, а все что осталось под кучу? Но с таким-же успехом можно и в конце фиксированный под стек, а весь остаток под кучу. Главное. что ВЕСЬ а не какой-то опять-же фиксированный размер. Размер хипа следует указывать только минимальный, дабы уже линкер ругался, что совсем уж памяти не хватает.
QUOTE (zltigo @ Apr 18 2016, 15:13) *
RTOS сама ничего и нигде не размещает. Размещает линкер я соответствии с указаниями данными Вами лично.

Возможно я здесь чего то не понял. RTOS использует собственный стек и кучу, или те же что и компилятор (у меня GCC)? В настройках RTOS есть 2 параметра:
QUOTE
#define configMINIMAL_STACK_SIZE
#define configTOTAL_HEAP_SIZE

Получается что этими параметрами я задаю имеющуюся память в МК, потому что RTOS не имеет представления о том что у него на борту?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 18 2016, 13:47
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



QUOTE (maxntf @ Apr 18 2016, 15:34) *
Тогда мне не понятно, зачем делать, чтоб куча шла на встречу стеку? Почему не выделить вначале кусок памяти под стек, а все что осталось под кучу?

Такое мне больше всего нравится, так и делаю.
QUOTE
Возможно я здесь чего то не понял. RTOS использует собственный стек и кучу, или те же что и компилятор (у меня GCC)? В настройках RTOS есть 2 параметра:

FreeRTOS использует какую-то кучу, какую, зависит то того, какой менеджер памяти в проект закинули. В том числе может использовать "свою". Для этого случая есть параметр размера в конфигурации.
А стек в конфигурации FreeRTOS, это СОВСЕМ из другой оперы! Стек, это уже стек КАЖДОЙ из задач, ибо у каждой он свой.
QUOTE
Получается что этими параметрами я задаю имеющуюся память в МК

Нет, требуемую Вам память в пределах имеющейся.
QUOTE
, потому что RTOS не имеет представления о том что у него на борту?

А как, простите, она может иметь представление? Конечно не имеет.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 18 2016, 13:49
Сообщение #11


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(maxntf @ Apr 18 2016, 17:01) *
- из этого понятно что верх стека по адресу 0x20000888 + 0x800(размер стека) = 0x20001088. Это значение записано и по адресу 0x08000000. За адресом 0x20001088 у нас больше ничего уже не будет хранится.

Непонятно, как это у вас получилось. Судя по отрывку из заглавного поста этой темы:
Код
    /* Set stack top to end of ram , and stack limit move down by
    * size of stack_dummy section */
    __StackTop = ORIGIN(ram ) + LENGTH(ram );
    __StackLimit = __StackTop - SIZEOF(.co_stack);
    PROVIDE(__stack = __StackTop);

У вас по адресу 0x08000000 должен быть записан адрес конца ОЗУ (0x20020000).

Цитата(maxntf @ Apr 18 2016, 17:01) *
то есть в данном случае я могу увеличить размер стека до значения 0x20020000 - 0x20000888(до этого адреса хранятся глобальные переменные).

Да поймите же, что "размер стека" и "размер кучи" - это просто для контроля достаточности свободного места. Если у вас сумма "размер стека + размер кучи" меньше свободного ОЗУ, то всё в порядке.
Цитата(maxntf @ Apr 18 2016, 17:01) *
Теоретически куча может не то что встретится со стеком, а стереть его полностью, добравшись до точки В. То же самое может сделать и стек с кучей, если он доберется до точки А. Так?

Неважно, как это назвать. Если у вас пересеклись куча и стек хотя бы на байт, значит, памяти не хватило.
Цитата(maxntf @ Apr 18 2016, 17:01) *
Если нужна локальная переменная большого размера, а точнее мы не знаем какого размера она будет, но знаем что может быть большой - лучше ей память выделить динамически из кучи то-есть области ближе к точке А.

Какая разница, откуда выделить место для большой переменной? Всё равно это будет кусок вашего свободного ОЗУ. Либо вы откусите кусок сверху, либо снизуsm.gif
Цитата(maxntf @ Apr 18 2016, 17:01) *
По факту мы не имеем каких то конкретных размеров стека и кучи. Размер стека от заданной его вершины и до начала локальных данных. Размер кучи с начала памяти локальных данных и до конца памяти.

Да.
Цитата(maxntf @ Apr 18 2016, 17:01) *
Превышение лимита стека контролируется вылетом в прерывание HardFault (если такое происходит, значит полная же.. и нужно делать переорганизацию памяти, увеличивать стек или выбирать проц с большей памятью.

Нет, превышение лимита стека не контролируется.
Цитата(maxntf @ Apr 18 2016, 17:01) *
Превышение лимита кучи контролируется через некое ограничивающее значение, наверное __HeapLimit, если вообще контролируется это. На сколько я понял этот контроль настраивается в функции _sbrk, ее специально оставили пользователю. То есть там нужно сделать проверку, если пытаемся выделить память за пределами HeapLimit, тогда не выделять память.

Да, так можно сделать. Сделано ли это - посмотрите в _sbrk().

Цитата(maxntf @ Apr 18 2016, 17:01) *
[*] Это значение HeapLimit должно ведь быть динамическим. Ну типа до указателя стека, стек вырос и HeapLimit уменьшилось, стек уменьшился и HeapLimit увеличился? Иначе зачем тогда стек и кучу пихать в один сегмент памяти!

Нет, это просто такая засечка посередине между началом кучи и вершиной стека. Можно на неё поглядывать в процессе выделения памяти.
Цитата(maxntf @ Apr 18 2016, 17:01) *
[*] Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу?

А это зависит от того, что за RTOS. Куча может быть общая и для RTOS и без RTOS, а стеки процессов выделяются из области переменных.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
maxntf
сообщение Apr 18 2016, 15:05
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



Цитата(AHTOXA @ Apr 18 2016, 16:49) *
Непонятно, как это у вас получилось. Судя по отрывку из заглавного поста этой темы:
У вас по адресу 0x08000000 должен быть записан адрес конца ОЗУ (0x20020000).
С этим вроде понял. Все дело в файле starup который coocox включает при выборе в репозитории компонента CMSIS BOOT. Не понятно зачем так?
Код
/*----------Stack Configuration-----------------------------------------------*/
#define STACK_SIZE       0x00002000      /*!< The Stack size suggest using even number    */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];

__attribute__ ((used,section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
  /*----------Core Exceptions------------------------------------------------ */
  (void *)&pulStack[STACK_SIZE],     /*!< The initial stack pointer           */
  Reset_Handler,             /*!< Reset Handler                               */
ля-ля-ля
}

В общем я поменял кусок, и теперь и стек начинается с __StackTop что в линкере указан, и проверка сохраняется ASSERT(__StackLimit >= __HeapLimit, "region ram overflowed with stack")
Код
/*----------Stack Configuration-----------------------------------------------*/
#define STACK_SIZE       0x00002000      /*!< The Stack size suggest using even number    */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];

extern unsigned long __stack;
__attribute__ ((used,section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
  /*----------Core Exceptions------------------------------------------------ */
  (void *)&__stack,     /*!< The initial stack pointer           */
  Reset_Handler,             /*!< Reset Handler                               */


Цитата(AHTOXA @ Apr 18 2016, 16:49) *
Да поймите же, что "размер стека" и "размер кучи" - это просто для контроля достаточности свободного места. Если у вас сумма "размер стека + размер кучи" меньше свободного ОЗУ, то всё в порядке.
Вот теперь после изменения startup и понял.

Цитата(AHTOXA @ Apr 18 2016, 16:49) *
Да, так можно сделать. Сделано ли это - посмотрите в _sbrk().
Вот что у меня в этой функции.
Код
extern int  _end;
/*This function is used for handle heap option*/
__attribute__ ((used))
caddr_t _sbrk ( int incr )
{
    static unsigned char *heap = NULL;
    unsigned char *prev_heap;

    if (heap == NULL) {
        heap = (unsigned char *)&_end;
    }
    prev_heap = heap;

    heap += incr;

    return (caddr_t) prev_heap;
}

На сколько я понял _end это та что в линкере
Код
    .heap (COPY):
    {
        __end__ = .;
        _end = __end__;
        end = __end__;
        *(.heap*)
        __HeapLimit = .;
    } > ram

Не пойму как устанавливается значение __HeapLimit? И что в _sbrk нужно добавить, чтоб запретить выделять память после этого HeapLimit?
Цитата(AHTOXA @ Apr 18 2016, 16:49) *
А это зависит от того, что за RTOS. Куча может быть общая и для RTOS и без RTOS,
FreeRTOS.
Цитата(AHTOXA @ Apr 18 2016, 16:49) *
а стеки процессов выделяются из области переменных.
Глобальных переменных, области data и bss?

Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 18 2016, 16:43
Сообщение #13


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(maxntf @ Apr 18 2016, 20:05) *
С этим вроде понял. Все дело в файле starup который coocox включает при выборе в репозитории компонента CMSIS BOOT. Не понятно зачем так?

Да кто ж их знаетsm.gif Может, была какая-то причина, а может, сделали как сумели.
Цитата(maxntf @ Apr 18 2016, 20:05) *
В общем я поменял кусок, и теперь и стек начинается с __StackTop что в линкере указан, и проверка сохраняется ASSERT(__StackLimit >= __HeapLimit, "region ram overflowed with stack")

Отлично.
Цитата(maxntf @ Apr 18 2016, 20:05) *
Не пойму как устанавливается значение __HeapLimit?

У вас же там объявлена переменная специальная, и помещена в секцию .heap:
Код
/*----------Heap Configuration-----------------------------------------------*/
#define HEAP_SIZE       0x00001000
__attribute__ ((section(".heap")))
unsigned long pulHeap[HEAP_SIZE];

Соответственно, этот кусок скрипта линкера
Код
    .heap (COPY):
    {
        __end__ = .;
        _end = __end__;
        end = __end__;
        *(.heap*)
        __HeapLimit = .;
    } > ram

ставит засечку "_end", а через HEAP_SIZE слов после неё - засечку __HeapLimit.
Цитата(maxntf @ Apr 18 2016, 20:05) *
И что в _sbrk нужно добавить, чтоб запретить выделять память после этого HeapLimit?

Как-то так:
Код
caddr_t _sbrk ( int incr )
{
    static unsigned char *heap = NULL;
    unsigned char *prev_heap;
    unsigned char *new_heap;

    if (heap == NULL) {
        heap = (unsigned char *)&_end;
    }
    prev_heap = heap;
    new_heap = heap + incr;
    if (new_heap > (unsigned char *)&__HeapLimit) {
        return 0;
    }
    heap = new_heap;
    return (caddr_t) prev_heap;
}


Цитата(maxntf @ Apr 18 2016, 20:05) *
FreeRTOS.

Тут я точно не знаю, сочинять не буду. Спросите у zltigo, он спец по FreeRTOS.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
maxntf
сообщение Apr 19 2016, 09:59
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 107
Регистрация: 13-05-09
Пользователь №: 49 008



Вух!!!, вроде все понял. Много вопросов отпало, когда собралась общая картинка. Просто начал я не с того боку и все из за того базового линк. Нужно было начинать с его ковыряния, а не кода Си.
Вот линк:
Код
_eram = 0x20000000 + 0x00020000;

SECTIONS
{
    .text :
    {
        KEEP(*(.isr_vector))
                ля-ля-ля
        } > rom
        .data :
    {
         ля-ля-ля
    } > ram
    .bss :
    {
         ля-ля-ля
    } > ram

//Начало моей части где я настраиваю stack & heap
//Стек
    _stack_size = 0x200;/*Размер - нужно только мне и для вычисления след. параметров*/
    _StackTop = . + _stack_size;/*Вершина стека начало лок. данных + его размер*/
    _StackLimit = .;/*Для наглядности - начало лок. данных*/
    .stack :/*Это собственно секция стека*/
        {
        . = . + _stack_size;/*установка размера этой секции*/
        } > ram
    PROVIDE(_stack = _StackTop);/*значение _stack устанавливаем в _StackTop*/
                                                      /*_stack потом помещаем в начало вектора*/
//Куча
    _heap_size = 0x100;/*размер кучи*/
    _heap_begin = _eram - _heap_size;/*адрес начала кучи*/    
    _heap_limit = _heap_begin + _heap_size;/*лимит кучи для проверки*/
    .heap (_heap_begin):/*секцию под кучу располагаем адреса _heap_begin*/  
        {
        . = . + _heap_size;/*установка размера этой секции*/
        } > ram     
}

В startup файле устанавливаем только координаты начала стека, больше в нем нет ничего про стек и кучу!
Код
extern unsigned long _stack;//значение задано в линк. файле
__attribute__ ((used,section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
  /*----------Core Exceptions------------------------------------------------ */
  (void *)&_stack,           /*!< The initial stack pointer                   */
  Reset_Handler,             /*!< Reset Handler                               */
  NMI_Handler,               /*!< NMI Handler                                 */

Для проверки переполнения кучи в файле syscalls.c
Код
extern int  _heap_begin;
extern int  _heap_limit;
caddr_t _sbrk ( int incr )
{
    static unsigned char *heap = NULL;
    unsigned char *prev_heap;
    unsigned char *new_heap;
    if (heap == NULL) {
        heap = (unsigned char *)&_heap_begin;
    }
    prev_heap = heap;
    new_heap = heap + incr;
    if(new_heap > (unsigned char *)&_heap_limit) {
        return 0;
    }
    heap = new_heap;
    return (caddr_t) prev_heap;
}

По map файлу (просто для наглядности):
В итоге мы получили стек размером 0x200 который идет с адреса 0x20000a88 к 0x20000888.
Куча которая начинается с адреса 0x2001ff00 и идет до конца памяти с ограничением переполнения.
Код
COMMON         0x20000884        
                0x20000884                errno
                0x20000888                . = ALIGN (0x4)
                0x20000888                __bss_end__ = .
                0x20000888                _ebss = __bss_end__
                0x00000200                _stack_size = 0x200
                0x20000a88                _StackTop = (. + _stack_size)
                0x20000888                _StackLimit = .

.stack          0x20000888      0x200 load address 0x080014b4
                0x20000a88                . = (. + _stack_size)
*fill*         0x20000888      0x200
                0x20000a88                PROVIDE (_stack, _StackTop)
                0x00000100                _heap_size = 0x100
                0x2001ff00                _heap_begin = (_eram - _heap_size)
                0x20020000                _heap_limit = (_heap_begin + _heap_size)

.heap           0x2001ff00      0x100 load address 0x08020b2c
                0x2001ff00                _end = .
                0x20020000                . = (. + _heap_size)
*fill*         0x2001ff00      0x100


Остался один вопрос:
Эти самые секции объявляются для того, чтоб в эти места памяти никто ничего левого не подсунул?
Типа ка в линке MCC18 под ПИК когда нужна секция, в которую линкер ничего не суют?
Цитата
DATABANK NAME=bgpr2 START=0x500 END=0x6FF PROTECTED

Или то-же только для наглядности?
И здесь и так никто ничего не подсунет. Все глобальные переменные по порядочку по секциям data и bss (в PIC они были разбросаны по банкам памяти). Стек от А до В, куча от С до D. Все локальные переменные в стеке.
Тогда может вообще лишнее объявлять эти секции?
Сделать себе
Код
_stack_size = 0x200;
_StackTop = . + _stack_size;
PROVIDE(_stack = _StackTop);
//Куча
_heap_size = 0x100;
_heap_begin = _eram - _heap_size;
_heap_limit = _heap_begin + _heap_size;

И Все?!
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 19 2016, 10:48
Сообщение #15


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(maxntf @ Apr 19 2016, 14:59) *
В итоге мы получили стек размером 0x200 который идет с адреса 0x20000a88 к 0x20000888.
Куча которая начинается с адреса 0x2001ff00 и идет до конца памяти с ограничением переполнения.

Вы опять поменяли местами стек и кучуsm.gif
Ну что же, если вам так нравится, то пусть будет так. Хотя мне больше по душе вариант, когда стек начинается в конце ОЗУ.
Цитата(maxntf @ Apr 19 2016, 14:59) *
Остался один вопрос:
Эти самые секции объявляются для того, чтоб в эти места памяти никто ничего левого не подсунул?

Если размер этих секций превысит свободное ОЗУ, то вы получите ошибку линковки. А так - да, можно и без этих секций, просто объявить _stack, _heap_begin и _heap_limit.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 16th June 2025 - 22:24
Рейтинг@Mail.ru


Страница сгенерированна за 0.01577 секунд с 7
ELECTRONIX ©2004-2016