Прошу прошения за сумбурность, просто вопросов много, а тема одна. Проект я делаю в CooCox, так что прошу понять и простить и не предлагать кейлы, иары итп IDE знаю, но хочу именно в CooCox. В общем, думал я насчет того, как лучше отделить переменные в памяти RAM, переменные чисто по смыслу относятся к разным пространствам, одни используются совместно с системными функциями (работа периферией), другие относятся к прикладным и должны быть отделены во-первых для удобства размещения, во-вторых, их хочется использовать для обмена по Модбасу и потому в кучу все мешать не охота. Может это и надуманное решение, но захотелось мне стек разместить вершиной не в конце ram, а где-то со смещением относительно конца ram, так чтоб как раз хватило места на вторую группу переменных. Тут я столкнулся с некоторыми неудобствами и приколами. 1. Как лучше всего переместить стек? Для CooCox наверное единственным путем это будет настройка адреса вершины стека в ld файле скрипта линкера, так для моего STM32F103RB память выглядит так:
соответственно в скрипте я ставил свои сегменты и секции с явным указанием адреса
Код:
.My_Ram_Segment 0x20003000 : {KEEP(*(.My_section))} /*здесь можно было даже дописать после } отсыл к >ram1*/
А все, что по дефолту стояло, я отослал к ram0, так, что даже переделывать особо ничего не пришлось. Тут возникала некоторая проблемка - бинарник раздумало до 400 мегабайт, причем он отличался от финального (когда я отказался от идеи двух разделов ram) тем, что он был заполнен нулями до конца, а начало один в один совпадало. Внимание вопрос как же быть, можно ли делить ram и как это правильно делать?
2. заметил, что мой CooCox как-то странно ведет себя со стеком и памятью ram как раз где-то на границе, где этот стек реально размещен (это я про регистр sp - указатель на текущий адрес стека). Короче, sp указывал на адрес в районе 0x20001000, причем ему было все равно, где я указывал положение вершины стека в скрипте линкера, и все равно на деление ram (проверял и когда отказался от идеи делить память и в тестовом проекте вообще без помещения в скрипт линкера своих сегментов с явным указанием адреса размещения). Вопрос: почему он шел не от вершины, ведь до нее было очень и очень далеко? Вторая половина вопроса номер два про мусор, ведь насколько я понимаю оперативная память после сброса питания должна быть обнулена? Я сейчас не про программное обнуление, например, как для секции bss, которое прописано в стартап-файле типа startup_stm32f10x_md.c, а про вообще начальное состояние памяти. Так вот, все что до адреса, указанного в стеке (не точно конечно по этому адресу, но близко к нему) было обнулено, а все вплоть до адреса 0x20005000 (причем это как при определении адреса вершины стека равной 0x20003000, так и при 0x20005000) было заполнено каким-то информационным мусором (даже близко не похожим на адреса или какие-то данные из программы). Что это может быть? Ну и хотелось бы услышать Ваше мнение по размещению стека не по дефолту, у меня сейчас вот так:
/* .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
/* Set stack top to end of ram , and stack limit move down by * size of stack_dummy section */ __StackTop = ORIGIN(ram ) + LENGTH(ram ) - 0x2000; __StackLimit = __StackTop - SIZEOF(.co_stack); PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds ram limit */ ASSERT(__StackLimit >= __HeapLimit, "region ram overflowed with stack")
а в стартапе вот так:
Код:
/*---------- Configuration-----------------------------------------------*/ #define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */ __attribute__ ((section(".co_stack"))) unsigned long pulStack[STACK_SIZE];
Последний раз редактировалось auric Чт окт 17, 2019 10:13:41, всего редактировалось 1 раз.
думал я насчет того, как лучше отделить переменные в памяти RAM, переменные чисто по смыслу относятся к разным пространствам, одни используются совместно с системными функциями (работа периферией), другие относятся к прикладным и должны быть отделены во-первых для удобства размещения, во-вторых, их хочется использовать для обмена по Модбасу и потому в кучу все мешать не охота
Любопытно, для чего нужны эти телодвижения. Пишете на "ассемблере с элементами С"? Просто интересно.
Это называется "горе от ума". Не надо мешать компилятору и линкеру делать своё дело. Если хочется что-то от чего-то изолировать, то можно в разных единицах трансляции сделать. Мало? В пространства имён загоните.
Добавлено after 5 minutes 36 seconds: Не, ну правда, зачем переменные в памяти разносить? Они что, покусают друг друга? Или продифундируют?
Еще раз тезисно опишу интересующие меня вопросы, чтобы дискус не отклонялся от темы, тк проблемы, что мне мешали, я и так сам решил, остальное мне больше интересно в общеобразовательных целях. 1. можно ли делить ram и как это правильно делать? Примеры подобные с деление FLASH я видел. 2.а ссылается ли у вас регистр sp на прописанную в скрипте линковщика вершину стека (условно конечно, тк вызов любой функции и другая работа STM естественно должны уменьшить адрес в регистре sp, но каждый зная свою программу примерно представляет отклонение от вершины) 2.б я мельком находил информацию про "вспышку при запуске RAM" и иных таких вот процессах, но ничего конкретного, но мне почему-то казалось, что RAM после включения STM должна содержать нули до обращения к ней, прошу так сказать подтвердить или опровергнуть возможность появления в какой-то области RAM такого "информационного мусора" в виде ненулевых данных и вероятность отсутствия его в другой (звучит как бред, но я это наблюдал). ну и напоследок интересно про опыт по размещению стека не по дефолту, то есть например со смещением вершины от конца RAM или вовсе в начале, может кто-то вообще разворачивал движение стека в сторону наращивания адреса.
При включении питания в RAM находятся случайные данные. Стартовый код программы принудительно обнуляет глобальные неинициализированные переменные и записывает начальные значения в инициализированные. После чего вызывает конструкторы глобальных объектов, если код на С++, и передаёт управление в main.
Заголовок сообщения: Re: Мусор в ram, размещение стека не по дефлту, разбивка ram
Добавлено: Ср окт 16, 2019 21:10:04
Друг Кота
Карма: 38
Рейтинг сообщений: 621
Зарегистрирован: Пн апр 06, 2015 11:01:53 Сообщений: 3092 Откуда: москва, уфа
Рейтинг сообщения:1
1. Можно, как раз скриптами линкера. Но это бывает редко нужно - к примеру, если прицепляете внешнюю SRAM в дополнение к внутренней или что-то уж очень хитрое делаете с бутлоадером. Даже RTOS-ы со всякими отдельными стеками под каждую задачу и собственными аллокаторами памяти в куче обычно туда не лезут.
2а. SP инициализируется значением, с которого начинается таблица векторов прерываний. Задается в startup файле.
2б. Без принудительно инициализации в RAM мусор, да. Нулями забивается программно в том же startup файле, дефолтно только BSS.
стек можно разместить и иногда размещают по-разному, но, опять же, непонятно, зачем. По крайней мере от меня смысл ускользает - стандартное расположение и направление вполне логично и разумно. "Развернуть" стек принципиально можно, но это развлечение скорее для ассемблерщиков - ибо в С попросить линкер подвинуть адреса еще можно, но способа сказать компилятору использовать другие команды для доступа к данным в стеке я не знаю.
Прошу прощения, только потом заметил, что не новый пост добавил а редактировал предыдущий, ответ Мурику и arkhnchul будут здесь. Видать движок так работает, чтоб несколько постов одного автора не набивать.
При включении питания в RAM находятся случайные данные. Стартовый код программы принудительно обнуляет глобальные неинициализированные переменные и записывает начальные значения в инициализированные. После чего вызывает конструкторы глобальных объектов, если код на С++, и передаёт управление в main.
если правильно понимаю в стартапе это void Default_Reset_Handler(void), в ней есть секция ASM:
Код:
/* Zero fill the bss segment. This is done with inline assembly since this will clear the value of pulDest if it is not kept in a register. */ __asm(" ldr r0, =_sbss\n" " ldr r1, =_ebss\n" " mov r2, #0\n" " .thumb_func\n" "zero_loop:\n" " cmp r0, r1\n" " it lt\n" " strlt r2, [r0], #4\n" " blt zero_loop");
Поставив точку останова до этой секции залез в память и там почему-то уже стояли условно обнуленными (за исключением единичных ячеек, с которыми я разбираться не стал) первая часть RAM (в том числе и относящаяся к bss). Правда за чистоту эксперимента стал сейчас сомневаться, тк питания сбрасывал исключительно до погасания светодиодов, может в памяти "энергии" дольше держатся. За информацию спасибо, а где можно почитать про это явление (про память именно на STMках)? Может поисковый запрос какой-то хитрый по ключевым словам подскажите про это явление, до этого искал, не встречал конкретики именно про STM32.
Короче, sp указывал на адрес в районе 0x20001000, причем ему было все равно, где я указывал положение вершины стека в скрипте линкера
Смотрите стартап файл, в котором расположена таблица прерываний и адрес начала стека.
Спасибо за внимание к вопросу! Что касается стартапа, я брал стандартный CooCox, там все что касается стека:
Код:
/*---------- Configuration-----------------------------------------------*/ #define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */ __attribute__ ((section(".co_stack"))) unsigned long pulStack[STACK_SIZE];
Остальное в скрипте и там вот что:
Код:
/* .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
/* Set stack top to end of ram , and stack limit move down by * size of stack_dummy section */ __StackTop = ORIGIN(ram ) + LENGTH(ram ) - 0x2000; __StackLimit = __StackTop - SIZEOF(.co_stack); PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds ram limit */ ASSERT(__StackLimit >= __HeapLimit, "region ram overflowed with stack")
Откуда взялось .co_stack 0x20000c18 0x400 ..\obj\startup_stm32f10x_md.o ? у меня вроде как #define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */ Ну про остальные сдвиги уже писал (чешу тыковку)...
1. Можно, как раз скриптами линкера. Но это бывает редко нужно - к примеру, если прицепляете внешнюю SRAM в дополнение к внутренней или что-то уж очень хитрое делаете с бутлоадером. Даже RTOS-ы со всякими отдельными стеками под каждую задачу и собственными аллокаторами памяти в куче обычно туда не лезут.
Ну вот я встречал, когда память на старших моделях СТМ имеет реально разные группы адресов, так как раз две группы памяти, по кейлу помню, там если без скрипта собственными настройками тоже была возвожность делить, а как это правильно делать, я так и не понял, потому как работало, но криво. Про бинарник уже писал. Хотя сама программа при этом грузилась и работала без ошибок. Теперь чисто для самообразования хотел закрыть этот вопрос, тк как раз со своим самописным хитрым бутлоадером потом хотел что-то замутить в этом проекте.
2а. SP инициализируется значением, с которого начинается таблица векторов прерываний. Задается в startup файле.
Да это в самом самом начале запуска кода, я же говорю про другие этапы, следующие, когда он уже реально указывает на текущую позицию в стеке, она почему-то сильно далеко от своего ориентира - вершины стека, ну не может же по сути простая программа наполнить стек настолько, что он почти к концу подошел, ну мне по крайней мере не верится. К тому же меняя адрес вершины стека я ни на байт не сместил эти значения, проверял с разными настройками, стек стоит как "вкопанный", значит его что-то туда сориентировало.
стек можно разместить и иногда размещают по-разному, но, опять же, непонятно, зачем. По крайней мере от меня смысл ускользает - стандартное расположение и направление вполне логично и разумно. "Развернуть" стек принципиально можно, но это развлечение скорее для ассемблерщиков - ибо в С попросить линкер подвинуть адреса еще можно, но способа сказать компилятору использовать другие команды для доступа к данным в стеке я не знаю.
Тут тоже вопрос чисто для полноты картины понимания, сдвинуть как я понял не проблема (хотя сдвинуть точно на какую-то величину все-таки для меня пока проблема), а встречал где-то упоминания без конкретных примеров, что вроде как можно размещать стек и в начало и даже разворачивать ход его наполнения, вот это бы для себя хотелось так сказать либо опровергнуть либо подтвердить.
auric, ищите таблицу прерываний. Первой ячейкой будет адрес стека.
ета?
Код:
(void *)&pulStack[STACK_SIZE], /*!< The initial stack pointer */
если добавить это:
Код:
/*---------- Configuration-----------------------------------------------*/ #define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */ __attribute__ ((section(".co_stack"))) unsigned long pulStack[STACK_SIZE];
то получается, что __StackTop вовсе не вершина, хм....осталось разобраться откуда взялось .co_stack 0x20000c18 0x400 ..\obj\startup_stm32f10x_md.o
Откуда взялось .co_stack 0x20000c18 0x400 ..\obj\startup_stm32f10x_md.o ? у меня вроде как #define STACK_SIZE 0x00000100
ну Семен Семеныч) 0x100 чего?
Цитата:
#define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */ __attribute__ ((section(".co_stack"))) unsigned long pulStack[STACK_SIZE];
вообще говоря, линкер не распределяет и не размещает память под конкретно стек - только примерно прикидывает, не пересечется ли он с кучей. В оригинальном стартапе размер стека тоже подставляется линкером, но это не обязательно.
Откуда взялось .co_stack 0x20000c18 0x400 ..\obj\startup_stm32f10x_md.o ? у меня вроде как #define STACK_SIZE 0x00000100
ну Семен Семеныч) 0x100 чего?
Цитата:
#define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */ __attribute__ ((section(".co_stack"))) unsigned long pulStack[STACK_SIZE];
вообще говоря, линкер не распределяет и не размещает память под конкретно стек - только примерно прикидывает, не пересечется ли он с кучей. В оригинальном стартапе размер стека тоже подставляется линкером, но это не обязательно.
Точно long, в смысле даже не не в нем дело, я чет так заморочился с скриптом, что забыл, что забыл что STACK_SIZE может быть отнесен к чему угодно, в голове автоматом байт проставился))) ну все, хоть в этих вопросах пятен не оставил ))) спасибо
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 20
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения