Мусор в ram, размещение стека не по дефлту, разбивка ram

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
auric
Открыл глаза
Сообщения: 79
Зарегистрирован: Ср апр 17, 2019 12:04:23

Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение auric »

Прошу прошения за сумбурность, просто вопросов много, а тема одна. Проект я делаю в CooCox, так что прошу понять и простить и не предлагать кейлы, иары итп IDE знаю, но хочу именно в CooCox. В общем, думал я насчет того, как лучше отделить переменные в памяти RAM, переменные чисто по смыслу относятся к разным пространствам, одни используются совместно с системными функциями (работа периферией), другие относятся к прикладным и должны быть отделены во-первых для удобства размещения, во-вторых, их хочется использовать для обмена по Модбасу и потому в кучу все мешать не охота. Может это и надуманное решение, но захотелось мне стек разместить вершиной не в конце ram, а где-то со смещением относительно конца ram, так чтоб как раз хватило места на вторую группу переменных.
Тут я столкнулся с некоторыми неудобствами и приколами.
1. Как лучше всего переместить стек? Для CooCox наверное единственным путем это будет настройка адреса вершины стека в ld файле скрипта линкера, так для моего STM32F103RB память выглядит так:

Код: Выделить всё

MEMORY
{
	rom (rx)  : ORIGIN = 0x08000000, LENGTH = 0x00020000
	ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00005000
}
Пробовал разбить память на две группы (правда не совсем понимаю законно ли это, но вроде как работало, обращение к адресам второй группы шло)

Код: Выделить всё

{
	rom (rx)  : ORIGIN = 0x08000000, LENGTH = 0x00020000
	ram0 (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00003000
	ram1 (rwx) : ORIGIN = 0x20003000, LENGTH = 0x00002000
}
соответственно в скрипте я ставил свои сегменты и секции с явным указанием адреса

Код: Выделить всё

.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) было заполнено каким-то информационным мусором (даже близко не похожим на адреса или какие-то данные из программы).
Что это может быть?
Ну и хотелось бы услышать Ваше мнение по размещению стека не по дефолту, у меня сейчас вот так:

Код: Выделить всё

	.heap (COPY):
	{
		__end__ = .;
		_end = __end__;
		end = __end__;
		*(.heap*)
		__HeapLimit = .;
	} > ram 
	
	/* .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 раз.
Реклама
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение arkhnchul »

[uquote="auric",url="/forum/viewtopic.php?p=3719349#p3719349"]думал я насчет того, как лучше отделить переменные в памяти RAM, переменные чисто по смыслу относятся к разным пространствам, одни используются совместно с системными функциями (работа периферией), другие относятся к прикладным и должны быть отделены во-первых для удобства размещения, во-вторых, их хочется использовать для обмена по Модбасу и потому в кучу все мешать не охота[/uquote]Любопытно, для чего нужны эти телодвижения. Пишете на "ассемблере с элементами С"? Просто интересно.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение VladislavS »

Это называется "горе от ума". :) Не надо мешать компилятору и линкеру делать своё дело. Если хочется что-то от чего-то изолировать, то можно в разных единицах трансляции сделать. Мало? В пространства имён загоните.

Добавлено after 5 minutes 36 seconds:
Не, ну правда, зачем переменные в памяти разносить? Они что, покусают друг друга? Или продифундируют?
auric
Открыл глаза
Сообщения: 79
Зарегистрирован: Ср апр 17, 2019 12:04:23

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение auric »

Еще раз тезисно опишу интересующие меня вопросы, чтобы дискус не отклонялся от темы, тк проблемы, что мне мешали, я и так сам решил, остальное мне больше интересно в общеобразовательных целях.
1. можно ли делить ram и как это правильно делать? Примеры подобные с деление FLASH я видел.
2.а ссылается ли у вас регистр sp на прописанную в скрипте линковщика вершину стека (условно конечно, тк вызов любой функции и другая работа STM естественно должны уменьшить адрес в регистре sp, но каждый зная свою программу примерно представляет отклонение от вершины)
2.б я мельком находил информацию про "вспышку при запуске RAM" и иных таких вот процессах, но ничего конкретного, но мне почему-то казалось, что RAM после включения STM должна содержать нули до обращения к ней, прошу так сказать подтвердить или опровергнуть возможность появления в какой-то области RAM такого "информационного мусора" в виде ненулевых данных и вероятность отсутствия его в другой (звучит как бред, но я это наблюдал).
ну и напоследок интересно про опыт по размещению стека не по дефолту, то есть например со смещением вершины от конца RAM или вовсе в начале, может кто-то вообще разворачивал движение стека в сторону наращивания адреса.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение VladislavS »

При включении питания в RAM находятся случайные данные. Стартовый код программы принудительно обнуляет глобальные неинициализированные переменные и записывает начальные значения в инициализированные. После чего вызывает конструкторы глобальных объектов, если код на С++, и передаёт управление в main.
Реклама
Аватара пользователя
Мурик
Друг Кота
Сообщения: 3383
Зарегистрирован: Пн окт 11, 2010 19:00:08

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение Мурик »

auric писал(а):Короче, sp указывал на адрес в районе 0x20001000, причем ему было все равно, где я указывал положение вершины стека в скрипте линкера
Смотрите стартап файл, в котором расположена таблица прерываний и адрес начала стека.
auric писал(а):Вторая половина вопроса номер два про мусор, ведь насколько я понимаю оперативная память после сброса питания должна быть обнулена?
Она обнуляется программно в стартап файле. Аппаратно это не производится.
Реклама
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение arkhnchul »

1. Можно, как раз скриптами линкера. Но это бывает редко нужно - к примеру, если прицепляете внешнюю SRAM в дополнение к внутренней или что-то уж очень хитрое делаете с бутлоадером. Даже RTOS-ы со всякими отдельными стеками под каждую задачу и собственными аллокаторами памяти в куче обычно туда не лезут.

2а. SP инициализируется значением, с которого начинается таблица векторов прерываний. Задается в startup файле.

2б. Без принудительно инициализации в RAM мусор, да. Нулями забивается программно в том же startup файле, дефолтно только BSS.

стек можно разместить и иногда размещают по-разному, но, опять же, непонятно, зачем. По крайней мере от меня смысл ускользает - стандартное расположение и направление вполне логично и разумно. "Развернуть" стек принципиально можно, но это развлечение скорее для ассемблерщиков - ибо в С попросить линкер подвинуть адреса еще можно, но способа сказать компилятору использовать другие команды для доступа к данным в стеке я не знаю.
auric
Открыл глаза
Сообщения: 79
Зарегистрирован: Ср апр 17, 2019 12:04:23

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение auric »

Прошу прощения, только потом заметил, что не новый пост добавил а редактировал предыдущий, ответ Мурику и arkhnchul будут здесь. Видать движок так работает, чтоб несколько постов одного автора не набивать.

[uquote="VladislavS",url="/forum/viewtopic.php?p=3719535#p3719535"]При включении питания в RAM находятся случайные данные. Стартовый код программы принудительно обнуляет глобальные неинициализированные переменные и записывает начальные значения в инициализированные. После чего вызывает конструкторы глобальных объектов, если код на С++, и передаёт управление в main.[/uquote]
если правильно понимаю в стартапе это 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.

Добавлено after 10 minutes 17 seconds:
[uquote="Мурик",url="/forum/viewtopic.php?p=3719538#p3719538"]
auric писал(а):Короче, sp указывал на адрес в районе 0x20001000, причем ему было все равно, где я указывал положение вершины стека в скрипте линкера
Смотрите стартап файл, в котором расположена таблица прерываний и адрес начала стека.[/uquote]
Спасибо за внимание к вопросу! Что касается стартапа, я брал стандартный 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 load address 0x08003698
                0x20000c18                . = ALIGN (0x8)
 *(.co_stack .co_stack.*)
 .co_stack      0x20000c18      0x400 ..\obj\startup_stm32f10x_md.o
                0x20000c18                pulStack
                0x20003000                __StackTop = ((ORIGIN (ram) + LENGTH (ram)) - 0x2000)
                0x20002c00                __StackLimit = (__StackTop - SIZEOF (.co_stack))
                [!provide]                PROVIDE (__stack, __StackTop)
                0x00000001                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 */
Ну про остальные сдвиги уже писал (чешу тыковку)...
[uquote="Мурик",url="/forum/viewtopic.php?p=3719538#p3719538"]
auric писал(а):Вторая половина вопроса номер два про мусор, ведь насколько я понимаю оперативная память после сброса питания должна быть обнулена?
Она обнуляется программно в стартап файле. Аппаратно это не производится.[/uquote]
Понял, спасибо.

Добавлено after 12 minutes 41 second:
[uquote="arkhnchul",url="/forum/viewtopic.php?p=3719552#p3719552"]1. Можно, как раз скриптами линкера. Но это бывает редко нужно - к примеру, если прицепляете внешнюю SRAM в дополнение к внутренней или что-то уж очень хитрое делаете с бутлоадером. Даже RTOS-ы со всякими отдельными стеками под каждую задачу и собственными аллокаторами памяти в куче обычно туда не лезут.[/uquote]
Ну вот я встречал, когда память на старших моделях СТМ имеет реально разные группы адресов, так как раз две группы памяти, по кейлу помню, там если без скрипта собственными настройками тоже была возвожность делить, а как это правильно делать, я так и не понял, потому как работало, но криво. Про бинарник уже писал. Хотя сама программа при этом грузилась и работала без ошибок. Теперь чисто для самообразования хотел закрыть этот вопрос, тк как раз со своим самописным хитрым бутлоадером потом хотел что-то замутить в этом проекте.
[uquote="arkhnchul",url="/forum/viewtopic.php?p=3719552#p3719552"]2а. SP инициализируется значением, с которого начинается таблица векторов прерываний. Задается в startup файле.[/uquote]
Да это в самом самом начале запуска кода, я же говорю про другие этапы, следующие, когда он уже реально указывает на текущую позицию в стеке, она почему-то сильно далеко от своего ориентира - вершины стека, ну не может же по сути простая программа наполнить стек настолько, что он почти к концу подошел, ну мне по крайней мере не верится. К тому же меняя адрес вершины стека я ни на байт не сместил эти значения, проверял с разными настройками, стек стоит как "вкопанный", значит его что-то туда сориентировало.
[uquote="arkhnchul",url="/forum/viewtopic.php?p=3719552#p3719552"]2б. Без принудительно инициализации в RAM мусор, да. Нулями забивается программно в том же startup файле, дефолтно только BSS.[/uquote]
ок
[uquote="arkhnchul",url="/forum/viewtopic.php?p=3719552#p3719552"]стек можно разместить и иногда размещают по-разному, но, опять же, непонятно, зачем. По крайней мере от меня смысл ускользает - стандартное расположение и направление вполне логично и разумно. "Развернуть" стек принципиально можно, но это развлечение скорее для ассемблерщиков - ибо в С попросить линкер подвинуть адреса еще можно, но способа сказать компилятору использовать другие команды для доступа к данным в стеке я не знаю.[/uquote]
Тут тоже вопрос чисто для полноты картины понимания, сдвинуть как я понял не проблема (хотя сдвинуть точно на какую-то величину все-таки для меня пока проблема), а встречал где-то упоминания без конкретных примеров, что вроде как можно размещать стек и в начало и даже разворачивать ход его наполнения, вот это бы для себя хотелось так сказать либо опровергнуть либо подтвердить.
Аватара пользователя
Мурик
Друг Кота
Сообщения: 3383
Зарегистрирован: Пн окт 11, 2010 19:00:08

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение Мурик »

auric, ищите таблицу прерываний. Первой ячейкой будет адрес стека.
auric
Открыл глаза
Сообщения: 79
Зарегистрирован: Ср апр 17, 2019 12:04:23

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение auric »

[uquote="Мурик",url="/forum/viewtopic.php?p=3719799#p3719799"]auric, ищите таблицу прерываний. Первой ячейкой будет адрес стека.[/uquote]
ета?

Код: Выделить всё

(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
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение arkhnchul »

[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]искал, не встречал конкретики именно про STM32[/uquote]это общее свойство RAM. Вряд ли где-то заострен вопрос именно по стм-кам :dont_know:
[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]Что касается стартапа, я брал стандартный CooCox[/uquote]возьмите лучше обычный от ST, там оно имхо более прямолинейно.

[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]Откуда взялось .co_stack 0x20000c18 0x400 ..\obj\startup_stm32f10x_md.o ? у меня вроде как #define STACK_SIZE 0x00000100[/uquote]ну Семен Семеныч) 0x100 чего?
#define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];
[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]Остальное в скрипте и там вот что[/uquote]вообще говоря, линкер не распределяет и не размещает память под конкретно стек - только примерно прикидывает, не пересечется ли он с кучей. В оригинальном стартапе размер стека тоже подставляется линкером, но это не обязательно.
auric
Открыл глаза
Сообщения: 79
Зарегистрирован: Ср апр 17, 2019 12:04:23

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение auric »

[uquote="arkhnchul",url="/forum/viewtopic.php?p=3719822#p3719822"][uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]искал, не встречал конкретики именно про STM32[/uquote]это общее свойство RAM. Вряд ли где-то заострен вопрос именно по стм-кам :dont_know:
[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]Что касается стартапа, я брал стандартный CooCox[/uquote]возьмите лучше обычный от ST, там оно имхо более прямолинейно.

[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]Откуда взялось .co_stack 0x20000c18 0x400 ..\obj\startup_stm32f10x_md.o ? у меня вроде как #define STACK_SIZE 0x00000100[/uquote]ну Семен Семеныч) 0x100 чего?
#define STACK_SIZE 0x00000100 /*!< The Stack size suggest using even number */
__attribute__ ((section(".co_stack")))
unsigned long pulStack[STACK_SIZE];
[uquote="auric",url="/forum/viewtopic.php?p=3719713#p3719713"]Остальное в скрипте и там вот что[/uquote]вообще говоря, линкер не распределяет и не размещает память под конкретно стек - только примерно прикидывает, не пересечется ли он с кучей. В оригинальном стартапе размер стека тоже подставляется линкером, но это не обязательно.[/uquote]
Точно long, в смысле даже не не в нем дело, я чет так заморочился с скриптом, что забыл, что забыл что STACK_SIZE может быть отнесен к чему угодно, в голове автоматом байт проставился))) ну все, хоть в этих вопросах пятен не оставил ))) спасибо
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Re: Мусор в ram, размещение стека не по дефлту, разбивка ram

Сообщение arkhnchul »

[uquote="auric",url="/forum/viewtopic.php?p=3719816#p3719816"]ета?

Код: Выделить всё

(void *)&pulStack[STACK_SIZE],     /*!< The initial stack pointer         */
[/uquote]похоже на то. В стартапе ST без coocox-овых придумок все проще

Код: Выделить всё

...
  .section .isr_vector,"a",%progbits
  .type g_pfnVectors, %object
  .size g_pfnVectors, .-g_pfnVectors


g_pfnVectors:

  .word _estack
  .word Reset_Handler
  .word NMI_Handler
  .word HardFault_Handler
...
вот _estack - как раз адрес конца стека, его подставляет линкер, ибо в его скрипте

Код: Выделить всё

...
/* Highest address of the user mode stack */
_estack = 0x20005000;    /* end of RAM */
...
который, кстати, в этом скрипте больше вообще никак не используется :dont_know:
Ответить

Вернуться в «ARM»