Перейти к содержанию
    

Не получается настроить кучу в 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. Программа работает но там явно память выделяется за границами кучи.

post-49008-1460818205_thumb.jpg

Изменено пользователем maxntf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сначала вот вам картинка распределения ОЗУ:

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

 

Теперь пояснения.

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

Размер использованной кучи, скорее всего, не проверяется (можете посмотреть на функцию _sbrk() в syscalls.c. Максимум, что обычно делается - контролируется встреча кучи и стека. (И то далеко не всегда).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Размер использованной кучи, скорее всего, не проверяется (можете посмотреть на функцию _sbrk() в syscalls.c. Максимум, что обычно делается - контролируется встреча кучи и стека. (И то далеко не всегда).

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

Честно говоря я думал что стек и куча ограничиваются размером.

 

P.S.

  • сюда вы зачем-то засунули секцию co_stack

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

 

секция co_stack, вероятно, фальшивая.

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

Изменено пользователем maxntf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Ну, чтобы можно было проверить, что сумма стека и кучи поместится в ОЗУ.

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

Я вот про это:

2. В файле ld перенес сектор .heap который там уже был, под сектор .co_stack

Судя по всему, в исходном скрипте линкера было всё в соответствии с картой памяти, которую я нарисовал. А вы поменяли местами хип и стек.

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Во первых, огромное спасибо за наглядную картинку - сразу много вещей стало понятно!

:)

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

:)

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

Да нет, схему я как раз понял. Только в стандартном варианте было примерно так, в понедельник точный 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Из того что понятно:

post-49008-1460979113_thumb.jpg

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

post-49008-1460979647_thumb.jpg

Теоретически куча может не то что встретится со стеком, а стереть его полностью, добравшись до точки В. То же самое может сделать и стек с кучей, если он доберется до точки А. Так?

Стек растет сегментами, в которых хранятся локальные переменные функции и адрес возврата. Чем больше локальных переменных в функции, тем больше сегмент стека. Если нужна локальная переменная большого размера, а точнее мы не знаем какого размера она будет, но знаем что может быть большой - лучше ей память выделить динамически из кучи то-есть области ближе к точке А. И при этом стек у нас вырастет не значительно.

Про ограничения стека и кучи (как я это понял)!

По факту мы не имеем каких то конкретных размеров стека и кучи. Размер стека от заданной его вершины и до начала локальных данных. Размер кучи с начала памяти локальных данных и до конца памяти.

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

Превышение лимита кучи контролируется через некое ограничивающее значение, наверное __HeapLimit, если вообще контролируется это. На сколько я понял этот контроль настраивается в функции _sbrk, ее специально оставили пользователю. То есть там нужно сделать проверку, если пытаемся выделить память за пределами HeapLimit, тогда не выделять память.

 

А теперь собственно вопросы:

  • Это значение HeapLimit должно ведь быть динамическим. Ну типа до указателя стека, стек вырос и HeapLimit уменьшилось, стек уменьшился и HeapLimit увеличился? Иначе зачем тогда стек и кучу пихать в один сегмент памяти!
  • Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

[*] Это значение HeapLimit должно ведь быть динамическим.

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

[*] Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Разумеется нет.

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

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

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

#define configMINIMAL_STACK_SIZE

#define configTOTAL_HEAP_SIZE

Получается что этими параметрами я задаю имеющуюся память в МК, потому что RTOS не имеет представления о том что у него на борту?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тогда мне не понятно, зачем делать, чтоб куча шла на встречу стеку? Почему не выделить вначале кусок памяти под стек, а все что осталось под кучу?

Такое мне больше всего нравится, так и делаю.

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

FreeRTOS использует какую-то кучу, какую, зависит то того, какой менеджер памяти в проект закинули. В том числе может использовать "свою". Для этого случая есть параметр размера в конфигурации.

А стек в конфигурации FreeRTOS, это СОВСЕМ из другой оперы! Стек, это уже стек КАЖДОЙ из задач, ибо у каждой он свой.

Получается что этими параметрами я задаю имеющуюся память в МК

Нет, требуемую Вам память в пределах имеющейся.

, потому что RTOS не имеет представления о том что у него на борту?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

- из этого понятно что верх стека по адресу 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).

 

то есть в данном случае я могу увеличить размер стека до значения 0x20020000 - 0x20000888(до этого адреса хранятся глобальные переменные).

Да поймите же, что "размер стека" и "размер кучи" - это просто для контроля достаточности свободного места. Если у вас сумма "размер стека + размер кучи" меньше свободного ОЗУ, то всё в порядке.

Теоретически куча может не то что встретится со стеком, а стереть его полностью, добравшись до точки В. То же самое может сделать и стек с кучей, если он доберется до точки А. Так?

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

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

Какая разница, откуда выделить место для большой переменной? Всё равно это будет кусок вашего свободного ОЗУ. Либо вы откусите кусок сверху, либо снизу:)

По факту мы не имеем каких то конкретных размеров стека и кучи. Размер стека от заданной его вершины и до начала локальных данных. Размер кучи с начала памяти локальных данных и до конца памяти.

Да.

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

Нет, превышение лимита стека не контролируется.

Превышение лимита кучи контролируется через некое ограничивающее значение, наверное __HeapLimit, если вообще контролируется это. На сколько я понял этот контроль настраивается в функции _sbrk, ее специально оставили пользователю. То есть там нужно сделать проверку, если пытаемся выделить память за пределами HeapLimit, тогда не выделять память.

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

 

[*] Это значение HeapLimit должно ведь быть динамическим. Ну типа до указателя стека, стек вырос и HeapLimit уменьшилось, стек уменьшился и HeapLimit увеличился? Иначе зачем тогда стек и кучу пихать в один сегмент памяти!

Нет, это просто такая засечка посередине между началом кучи и вершиной стека. Можно на неё поглядывать в процессе выделения памяти.

[*] Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Непонятно, как это у вас получилось. Судя по отрывку из заглавного поста этой темы:

У вас по адресу 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                               */

 

Да поймите же, что "размер стека" и "размер кучи" - это просто для контроля достаточности свободного места. Если у вас сумма "размер стека + размер кучи" меньше свободного ОЗУ, то всё в порядке.
Вот теперь после изменения startup и понял.

 

Да, так можно сделать. Сделано ли это - посмотрите в _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?

А это зависит от того, что за RTOS. Куча может быть общая и для RTOS и без RTOS,
FreeRTOS.

а стеки процессов выделяются из области переменных.
Глобальных переменных, области data и bss?

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С этим вроде понял. Все дело в файле starup который coocox включает при выборе в репозитории компонента CMSIS BOOT. Не понятно зачем так?

Да кто ж их знает:) Может, была какая-то причина, а может, сделали как сумели.

В общем я поменял кусок, и теперь и стек начинается с __StackTop что в линкере указан, и проверка сохраняется ASSERT(__StackLimit >= __HeapLimit, "region ram overflowed with stack")

Отлично.

Не пойму как устанавливается значение __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.

И что в _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;
}

 

FreeRTOS.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вух!!!, вроде все понял. Много вопросов отпало, когда собралась общая картинка. Просто начал я не с того боку и все из за того базового линк. Нужно было начинать с его ковыряния, а не кода Си.

Вот линк:

_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;

И Все?!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В итоге мы получили стек размером 0x200 который идет с адреса 0x20000a88 к 0x20000888.

Куча которая начинается с адреса 0x2001ff00 и идет до конца памяти с ограничением переполнения.

Вы опять поменяли местами стек и кучу:)

Ну что же, если вам так нравится, то пусть будет так. Хотя мне больше по душе вариант, когда стек начинается в конце ОЗУ.

Остался один вопрос:

Эти самые секции объявляются для того, чтоб в эти места памяти никто ничего левого не подсунул?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...