maxntf 0 16 апреля, 2016 Опубликовано 16 апреля, 2016 (изменено) · Жалоба Не получается настроить кучу в 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. Программа работает но там явно память выделяется за границами кучи. Изменено 16 апреля, 2016 пользователем maxntf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 16 апреля, 2016 Опубликовано 16 апреля, 2016 · Жалоба Сначала вот вам картинка распределения ОЗУ: начало ОЗУ переменные переменные переменные сюда вы зачем-то засунули секцию co_stack начало кучи ↓куча растёт в сторону конца ОЗУ ↓куча растёт в сторону конца ОЗУ тут пусто тут пусто тут могут встретиться стек и ОЗУ тут пусто тут пусто ↑сюда растёт стек ↑сюда растёт стек начало стека (конец ОЗУ) Теперь пояснения. секция co_stack, вероятно, фальшивая. То есть, для дела важен только её размер. Вкупе со значением HEAP_SIZE это позволяет линкеру выдать ошибку, если суммарный размер стек+куча+переменные превысит размер ОЗУ. То, что вы поместили эту секцию после секции text и перед секцией .heap, просто оставило неиспользуемый кусок ОЗУ между переменными и кучей. Размер использованной кучи, скорее всего, не проверяется (можете посмотреть на функцию _sbrk() в syscalls.c. Максимум, что обычно делается - контролируется встреча кучи и стека. (И то далеко не всегда). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 16 апреля, 2016 Опубликовано 16 апреля, 2016 (изменено) · Жалоба начало ОЗУ переменные переменные переменные сюда вы зачем-то засунули секцию co_stack начало кучи ↓куча растёт в сторону конца ОЗУ ↓куча растёт в сторону конца ОЗУ тут пусто тут пусто тут могут встретиться стек и куча тут пусто тут пусто ↑сюда растёт стек ↑сюда растёт стек начало стека (конец ОЗУ) Во первых, огромное спасибо за наглядную картинку - сразу много вещей стало понятно! Редко на форуме понимают тех кто только начинает осваивать новое. Размер использованной кучи, скорее всего, не проверяется (можете посмотреть на функцию _sbrk() в syscalls.c. Максимум, что обычно делается - контролируется встреча кучи и стека. (И то далеко не всегда). Из вашего ответа, у меня напрашивается законный вопрос, почему на всех встречающихся примерах всегда указывается размер стека, и кучи? Честно говоря я думал что стек и куча ограничиваются размером. P.S. сюда вы зачем-то засунули секцию co_stack Это coocox делает по умолчанию в new_project. и GCC предлагает свой ld с таким расположением. секция co_stack, вероятно, фальшивая. Только вспомнил! По адресу 0х08000000 указан адрес 0х200055А8. То есть начало стека, так что получается что стек двигается с этого адреса в конец памяти? Изменено 16 апреля, 2016 пользователем maxntf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 16 апреля, 2016 Опубликовано 16 апреля, 2016 · Жалоба Из вашего ответа, у меня напрашивается законный вопрос, почему на всех встречающихся примерах всегда указывается размер стека, и кучи? Ну, чтобы можно было проверить, что сумма стека и кучи поместится в ОЗУ. Это coocox делает по умолчанию в new_project. и GCC предлагает свой ld с таким расположением. Я вот про это: 2. В файле ld перенес сектор .heap который там уже был, под сектор .co_stack Судя по всему, в исходном скрипте линкера было всё в соответствии с картой памяти, которую я нарисовал. А вы поменяли местами хип и стек. Только вспомнил! По адресу 0х08000000 указан адрес 0х200055А8. То есть начало стека, так что получается что стек двигается с этого адреса в конец памяти? Стек двигается в начало памяти. Поэтому начало стека обычно устанавливают в самый конец памяти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lmx2315 2 16 апреля, 2016 Опубликовано 16 апреля, 2016 · Жалоба Во первых, огромное спасибо за наглядную картинку - сразу много вещей стало понятно! :) Только вспомнил! По адресу 0х08000000 указан адрес 0х200055А8. То есть начало стека, так что получается что стек двигается с этого адреса в конец памяти? ..главное похвалить, а саму схему можно не читать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 16 апреля, 2016 Опубликовано 16 апреля, 2016 (изменено) · Жалоба :) ..главное похвалить, а саму схему можно не читать. Да нет, схему я как раз понял. Только в стандартном варианте было примерно так, в понедельник точный 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? Или я все не так понял? Изменено 16 апреля, 2016 пользователем maxntf Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба Вроде пришло понимание части вопросов! Что привело к возникновению еще большей "куче" вопросов. Из того что понятно: - из этого понятно что верх стека по адресу 0x20000888 + 0x800(размер стека) = 0x20001088. Это значение записано и по адресу 0x08000000. За адресом 0x20001088 у нас больше ничего уже не будет хранится. то есть в данном случае я могу увеличить размер стека до значения 0x20020000 - 0x20000888(до этого адреса хранятся глобальные переменные). Теоретически куча может не то что встретится со стеком, а стереть его полностью, добравшись до точки В. То же самое может сделать и стек с кучей, если он доберется до точки А. Так? Стек растет сегментами, в которых хранятся локальные переменные функции и адрес возврата. Чем больше локальных переменных в функции, тем больше сегмент стека. Если нужна локальная переменная большого размера, а точнее мы не знаем какого размера она будет, но знаем что может быть большой - лучше ей память выделить динамически из кучи то-есть области ближе к точке А. И при этом стек у нас вырастет не значительно. Про ограничения стека и кучи (как я это понял)! По факту мы не имеем каких то конкретных размеров стека и кучи. Размер стека от заданной его вершины и до начала локальных данных. Размер кучи с начала памяти локальных данных и до конца памяти. Превышение лимита стека контролируется вылетом в прерывание HardFault (если такое происходит, значит полная же.. и нужно делать переорганизацию памяти, увеличивать стек или выбирать проц с большей памятью. Превышение лимита кучи контролируется через некое ограничивающее значение, наверное __HeapLimit, если вообще контролируется это. На сколько я понял этот контроль настраивается в функции _sbrk, ее специально оставили пользователю. То есть там нужно сделать проверку, если пытаемся выделить память за пределами HeapLimit, тогда не выделять память. А теперь собственно вопросы: Это значение HeapLimit должно ведь быть динамическим. Ну типа до указателя стека, стек вырос и HeapLimit уменьшилось, стек уменьшился и HeapLimit увеличился? Иначе зачем тогда стек и кучу пихать в один сегмент памяти! Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба [*] Это значение HeapLimit должно ведь быть динамическим. Разумеется нет. Всегда есть явное или полуявное (типа вся свободная память) указание размера хипа. Менеджеры памяти никуда никакую память не растят, если запрошенное количество больше имеющейся. Явное указание есть тупейший вариант. С ним обычно для усугубления идет вариант, что все остальное стеку отдается - указывается минимально-отфонарное значение размера стека в рассчете на то, что свех этого будет еще какое то количество памяти нераспределенное линкером. [*] Если у нас верх стека это конец памяти, а начало кучи начало локальных данных где тогда ОС(в частности freertos) размещает свои стек и кучу? RTOS сама ничего и нигде не размещает. Размещает линкер я соответствии с указаниями данными Вами лично. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба Разумеется нет. Тогда мне не понятно, зачем делать, чтоб куча шла на встречу стеку? Почему не выделить вначале кусок памяти под стек, а все что осталось под кучу? Но с таким-же успехом можно и в конце фиксированный под стек, а весь остаток под кучу. Главное. что ВЕСЬ а не какой-то опять-же фиксированный размер. Размер хипа следует указывать только минимальный, дабы уже линкер ругался, что совсем уж памяти не хватает. RTOS сама ничего и нигде не размещает. Размещает линкер я соответствии с указаниями данными Вами лично. Возможно я здесь чего то не понял. RTOS использует собственный стек и кучу, или те же что и компилятор (у меня GCC)? В настройках RTOS есть 2 параметра: #define configMINIMAL_STACK_SIZE #define configTOTAL_HEAP_SIZE Получается что этими параметрами я задаю имеющуюся память в МК, потому что RTOS не имеет представления о том что у него на борту? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба Тогда мне не понятно, зачем делать, чтоб куча шла на встречу стеку? Почему не выделить вначале кусок памяти под стек, а все что осталось под кучу? Такое мне больше всего нравится, так и делаю. Возможно я здесь чего то не понял. RTOS использует собственный стек и кучу, или те же что и компилятор (у меня GCC)? В настройках RTOS есть 2 параметра: FreeRTOS использует какую-то кучу, какую, зависит то того, какой менеджер памяти в проект закинули. В том числе может использовать "свою". Для этого случая есть параметр размера в конфигурации. А стек в конфигурации FreeRTOS, это СОВСЕМ из другой оперы! Стек, это уже стек КАЖДОЙ из задач, ибо у каждой он свой. Получается что этими параметрами я задаю имеющуюся память в МК Нет, требуемую Вам память в пределах имеющейся. , потому что RTOS не имеет представления о том что у него на борту? А как, простите, она может иметь представление? Конечно не имеет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба - из этого понятно что верх стека по адресу 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, а стеки процессов выделяются из области переменных. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба Непонятно, как это у вас получилось. Судя по отрывку из заглавного поста этой темы: У вас по адресу 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? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 18 апреля, 2016 Опубликовано 18 апреля, 2016 · Жалоба С этим вроде понял. Все дело в файле 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
maxntf 0 19 апреля, 2016 Опубликовано 19 апреля, 2016 · Жалоба Вух!!!, вроде все понял. Много вопросов отпало, когда собралась общая картинка. Просто начал я не с того боку и все из за того базового линк. Нужно было начинать с его ковыряния, а не кода Си. Вот линк: _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; И Все?! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 19 апреля, 2016 Опубликовано 19 апреля, 2016 · Жалоба В итоге мы получили стек размером 0x200 который идет с адреса 0x20000a88 к 0x20000888. Куча которая начинается с адреса 0x2001ff00 и идет до конца памяти с ограничением переполнения. Вы опять поменяли местами стек и кучу:) Ну что же, если вам так нравится, то пусть будет так. Хотя мне больше по душе вариант, когда стек начинается в конце ОЗУ. Остался один вопрос: Эти самые секции объявляются для того, чтоб в эти места памяти никто ничего левого не подсунул? Если размер этих секций превысит свободное ОЗУ, то вы получите ошибку линковки. А так - да, можно и без этих секций, просто объявить _stack, _heap_begin и _heap_limit. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться