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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> IAR CSTACK RSTACK - измерение глубины стека
Mty
сообщение Apr 17 2016, 11:59
Сообщение #1


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Привет!

По идеям документа с сайта IAR
https://www.iar.com/support/resources/artic...em-reliability/
хочу напрямую смотреть использование стека в процессе выполнения программы

Идея в том, чтобы через таймерное прерывание периодически замерять указатель на автоматическую переменную, и мониторить сколько стека в использовании.
С data stack (CSTACK) все вроде должно получиться без проблем, а вот как получить указатель на текущий RSTACK?

C data stack идея такова -
Код
char *highStack, *lowStack;
int main(int argc, char *argv[])
{
highStack = (char *)&argc;
// ...
printf("Current stack usage: %d\n", highStack - lowStack);
}

void sampling_timer_interrupt_handler(void)
{
char* currentStack;
int a;
currentStack = (char *)&a;
if (currentStack < lowStack) lowStack = currentStack;
}


Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 17 2016, 16:02
Сообщение #2


Гуру
******

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



QUOTE (Mty @ Apr 17 2016, 14:59) *
Идея в том, чтобы через таймерное прерывание периодически замерять указатель на автоматическую переменную, и мониторить сколько стека в использовании.

Для контроля за использованим стеков их заполняют константными заначениями и переодически следят за их целостностью. Смысла в мгновенных сравнениях указателей стеков нет никакого.



--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Apr 17 2016, 16:56
Сообщение #3


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(zltigo @ Apr 17 2016, 19:02) *
Для контроля за использованим стеков их заполняют константными заначениями и переодически следят за их целостностью. Смысла в мгновенных сравнениях указателей стеков нет никакого.

+1 Тем более, что этот метод не является в прямом смысле "мгновенным", т. к. не позволяет уличить момент порчи стека, а в случае с AVR и никакой другой метод этого не позволит - AVR ядро не содержит таких аппаратных возможностей.
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Apr 17 2016, 17:09
Сообщение #4


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(Mty @ Apr 17 2016, 14:59) *
...Идея в том, чтобы через таймерное прерывание...


обычно привязывают к коду или потоку при выполнении которого портится стэк.
Либо как тут уже прозвучало выше - иметь аппаратные механизмы отслеживающие выход стэка за тот объём, что ему отведён.
Либо ставят анализатор на переключении контекста (в случае ОС).

Как превентивная мера - можно замерять сколько осталось(используется) по глубине стэк. И при изменении данного показателя производит запись
для дальнейшего анализа и разбора.

(круглый)
Go to the top of the page
 
+Quote Post
Mty
сообщение Apr 18 2016, 11:05
Сообщение #5


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Цитата(zltigo @ Apr 17 2016, 19:02) *
Для контроля за использованим стеков их заполняют константными заначениями и переодически следят за их целостностью. Смысла в мгновенных сравнениях указателей стеков нет никакого.


Ок, спасибо.
А есть пример как заполнить стеки константами, и получить указатель на начало в программе на рабочем девайсе (не в эмуляторе)?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 18 2016, 11:21
Сообщение #6


Гуру
******

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



QUOTE (Mty @ Apr 18 2016, 14:05) *
А есть пример как заполнить...

Как и любой массив памяти.
QUOTE
получить указатель на начало в программе на рабочем девайсе (не в эмуляторе)?

Поскольку стеки УСТАНАВЛИВАЮТСЯ при инициализации, а не назначаются господом богом, то "узнать" на самом деле означает посмотреть в программе где они устанавливаются (очевидно в cstartup). и/bли посмотреть имена сегментов в конфигурации линкера.


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


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Цитата(Mty @ Apr 17 2016, 14:59) *
С data stack (CSTACK) все вроде должно получиться без проблем, а вот как получить указатель на текущий RSTACK?


Так программно доступный регистр SP и есть указатель на RSTACK.
Go to the top of the page
 
+Quote Post
Mty
сообщение Apr 18 2016, 12:37
Сообщение #8


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Друзья, если у кого то есть рабочий код на С по заполнению стека при стартапе - буду признателен.

Пока нашел только это на ASM
http://caxapa.ru/301695.html?todo=full

PS: zltigo прошу не утруждать себя ответами.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 18 2016, 14:09
Сообщение #9


Гуру
******

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



QUOTE (Mty @ Apr 18 2016, 15:37) *
Пока нашел только это на ASM

Неправда. Там описан и абсолютно правильный путь и для IAR + Си. Только, как писал - "посмотреть имена сегментов в конфигурации линкера" таки придется.
Надо только думать, а не просто вопрошать "дайте рабочий код"
QUOTE
PS: zltigo прошу не утруждать себя ответами.

Без проблем.



--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
AleksBak
сообщение Apr 18 2016, 17:56
Сообщение #10


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

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



А почему у них там (у IAR) стек расположен не вверху памяти? А вверху памяти расположена куча? Непонятно что-то.




Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 18 2016, 17:59
Сообщение #11


Гуру
******

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



QUOTE (AleksBak @ Apr 18 2016, 20:56) *
А почему у них там (у IAR) стек расположен не вверху памяти?

А потому, что по барабану как, это раз. И IAR тут ни причем - дело хозяйское - как прикажете линкеру, так и будет.


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


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

Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364



Цитата(zltigo @ Apr 18 2016, 21:59) *
А потому, что по барабану как, это раз. И IAR тут ни причем - дело хозяйское - как прикажете линкеру, так и будет.

Еще вот как раз недавнюю тему почитал. Да - оказывается и так делают. Теперь надо бы переварить это... Посмотреть бы еще примеры под это дело (arm gcc).
Go to the top of the page
 
+Quote Post
zombi
сообщение Apr 18 2016, 23:37
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 076
Регистрация: 10-09-08
Пользователь №: 40 106



Цитата(Mty @ Apr 17 2016, 14:59) *
хочу напрямую смотреть использование стека в процессе выполнения программы

Вам правильно посоветовали использовать предварительное заполнение области стека константой с дальнейшим анализом содержимого оной.
Этот метод даст максимально точный результат. Хотя и не 100%.
А насколько точный результат глубины заполнения стека Вы хотите получить?
Go to the top of the page
 
+Quote Post
Mty
сообщение Apr 19 2016, 07:22
Сообщение #14


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Цитата(aiwa @ Apr 18 2016, 15:33) *
Так программно доступный регистр SP и есть указатель на RSTACK.


Спасибо, все оказывается просто sm.gif


Цитата(zombi @ Apr 19 2016, 02:37) *
Вам правильно посоветовали использовать предварительное заполнение области стека константой с дальнейшим анализом содержимого оной.
Этот метод даст максимально точный результат. Хотя и не 100%.
А насколько точный результат глубины заполнения стека Вы хотите получить?


Большой точности не надо, просто приблизительная оценка на реальной работе системы.

Способ с заполнением хорош, только вот примера на С рабочего нет. В примере по ссылке, про который я писал имена сегментов выставлены правильные, в map файле они так и называются CSTACK и RSTACK но пример нерабочий.

Код
char __low_level_init()
{
    #pragma segment="CSTACK"
    char* p = (char*)__segment_begin("CSTACK");
    size_t len = (size_t)__segment_end("CSTACK") - (size_t)__segment_begin("CSTACK");
    
    while( len-- )
        *p++ = 'C';
    
    p = (char*)__segment_begin("RSTACK");
    len = (size_t)__segment_end("RSTACK") - (size_t)__segment_begin("RSTACK");
    
    while( len-- )
        *p++ = 'R';

    return 1;
}
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 19 2016, 07:33
Сообщение #15


Гуру
******

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



QUOTE (Mty @ Apr 19 2016, 10:22) *
CODE
return 1;

Смотреть на "1". И думать что происходит при возврате 1 функцией __low_level_init

P.S.
Mty вышенаписаное читать не надо. Это только для тех, кому интересно, как это может не работать.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Mty
сообщение Apr 19 2016, 07:56
Сообщение #16


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Цитата(zltigo @ Apr 19 2016, 10:33) *
Смотреть на "1". И думать что происходит при возврате 1 функцией __low_level_init


Хорошо в EWAVR_CompilerReference.pdf

Код
The value returned by __low_level_init  determines whether or  not data segments  should be initialized by  the system startup code. If the function returns
0 , the data  segments will not be initialized.


Намекаете на то что при возврате 1 сегмент инициализируется 0 по выходе из функции?
А как же работает ASM вариант, который тоже возвращает 1 по той же ссылке?

И раз уж пошел конструктивный диалог, давайте предположим что может дело в том что в С варианте затирается весь RSTACK
а в ASM (SIZEOF RSTACK)-10)
Может в этом дело?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 19 2016, 08:04
Сообщение #17


Гуру
******

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



QUOTE (Mty @ Apr 19 2016, 10:56) *
Намекаете на то что при возврате 1 сегмент инициализируется 0 по выходе из функции?

Или не затирается, зависит от того в какой секции линкеру указано размещать стеки.
QUOTE
Может в этом дело?

Есественно, что из сишной (как и любой другой) функции которую ВЫЗВАЛИ и даже не первой в цепочке, полностью затирать стек ВОЗВРАТОВ нельзя. Затирать стек, инициализируя полностью можно только в стартапе, о чем сразу и писал. Чем вызвано Ваше такое дикое нежелание дописать несколько строк на ASM в стартапе?


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 19 2016, 08:30
Сообщение #18


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Осторожнее надо быть с RSTACKом, потому что такой код его может подпортить:

Код
p = (char*)__segment_begin("RSTACK");
    len = (size_t)__segment_end("RSTACK") - (size_t)__segment_begin("RSTACK");
    
    while( len-- )
        *p++ = 'R';


когда стартовый код вызывает __low_level_init, он заносит адрес возрата в RSTACK.
отступите от __segment_end("RSTACK") на величину адреса возврата.

И второе,
Код
char* p = (char*)__segment_begin("CSTACK");

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

Сообщение отредактировал aiwa - Apr 19 2016, 08:40
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 19 2016, 11:17
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Цитата
Намекаете на то что при возврате 1 сегмент инициализируется 0 по выходе из функции?
А как же работает ASM вариант, который тоже возвращает 1 по той же ссылке?

В старапе код эквивалентен такому:
Код
if(_low_level_init()!=0) _segment_init(); // отредактирована ошибка

Т.е. если _low_level_init вернула 0, то это означает, что программист желает, чтобы IAR произвел инициализацию сегментов,
в противном случае программист берет эти процедуры на себя.

Сообщение отредактировал aiwa - Apr 19 2016, 11:46
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 19 2016, 11:22
Сообщение #20


Гуру
******

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



QUOTE (aiwa @ Apr 19 2016, 14:17) *
Т.е. если _low_level_init вернула 0, то это означает, что программист желает, чтобы IAR произвел инициализацию сегментов,

C точностью до наоборот sad.gif


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 19 2016, 11:44
Сообщение #21


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Да, наоборот. Подправлю.

Кстати, нетрадиционное решение ИАРовцы приняли.
Логичней было бы пропускать инициализацию при возрате нуля.

Сообщение отредактировал aiwa - Apr 19 2016, 11:55
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 19 2016, 12:01
Сообщение #22


Гуру
******

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



QUOTE (aiwa @ Apr 19 2016, 14:44) *
Кстати, нетрадиционное решение ИАРовцы приняли.
Логичней было бы пропускать инициализацию при возрате нуля.

Так и сделано sm.gif


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Mty
сообщение Apr 19 2016, 12:32
Сообщение #23


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Насколько я понимаю он при инициализации сегментов не трогает стеки, а только загружает в DATA переменные?
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 19 2016, 13:29
Сообщение #24


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Цитата(zltigo @ Apr 19 2016, 15:01) *
Так и сделано sm.gif

Что-то у меня с утра не заладилось. Я имел в виду возврат ненулевого значения означает знак ИАРу, что инициализация сегементов уже выполнена,
а возврат 0 - выполнение инициализации ИАРом. Наподобие стандартной процедуры callback-функций, когда при возврате 0 производится стандартная
процедура по умолчанию.

Цитата(Mty @ Apr 19 2016, 15:32) *
Насколько я понимаю он при инициализации сегментов не трогает стеки, а только загружает в DATA переменные?


Порядок следующий:
1. в SP заносится значение конца RSTACKа,
2. в Y заносится значение конца СSTACKа,
если разрешена внешняя память, то соответствующая аппаратная инициализация.
Далее вызывается _low_level_init.
Если она вернула ненулевое значение, то вызывается процедура инициализации сегментов _segment_init (Эта процедура уже написана на С.)
И потом вызывается процедура построения статистических объектов классов.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 19 2016, 13:48
Сообщение #25


Гуру
******

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



QUOTE (Mty @ Apr 19 2016, 15:32) *
Насколько я понимаю он при инициализации сегментов не трогает стеки, а только загружает в DATA переменные?

Я уже писал - зависит от того, в каком сегменте память под стеки указана. Распределение смотреть у линкера.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 20 2016, 00:12
Сообщение #26


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Заинтересовало, по быстрому написал первоначальный вариант, но не проверял.
CODE
#pragma segment="RSTACK"
static __no_init unsigned char a[1] @ "RSTACK";
typedef char ( *point_to_lowlevelinit)(void);

char __low_level_init()
{
register unsigned int count=__segment_size("RSTACK")-1;
count-=sizeof(point_to_lowlevelinit);

while(count)
{
a[count]='R';
count--;
}
return 1;
}


Небольшие комментарии:
1. переменная а служит лишь меткой, для того чтобы компилятор занес в пару регистров начало RSTACKа
По хорошему нужно брать значение из переменной SP, которая уже отступила от вершины стека на 1 адрес.
2. переменная count описана как register чтобы надеяться, что компилятор не трогал софт-стек.
3. определение point_to_lowlevelinit введено лишь для получения размера адреса возврата который уже занесен
в стек - нужно отнять от это количество от count чтобы не затереть этот адрес.
Здесь в документации лучше бы найти более подходящий способ, наверняка должны быть какие-то системные константы.

Для заполнения софт-стека действуем аналогично.
Еще бы нужно добавить через pragma отключение оптимизации для этой функции.

Сообщение отредактировал aiwa - Apr 20 2016, 00:37
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 20 2016, 08:57
Сообщение #27


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Посмотрел с утра - код работать не будет. Не учел, что переменные ИАР располагает в сегментах от конца к началу, и что адресация флеш-памяти вдвое больше.

Этот код прошел в отладчике:
CODE
char __low_level_init()
{
register char* point=(char*)SP;
register char* pointtest=(char*)__segment_begin("RSTACK");

while(1)
{
*point='R';
point--;
if(point<pointtest) break;
}
return 1;
}

Для частных случаев работоспособен.

P.S. оказалось, что первоначальный вариант тоже работал, сбило то , под сегмент стека ИАР выделил "страницу" памяти и сам стек занимал в нем лишь половину. В том примере нужно лишь добавть инициализацию a[0]='R';

Сообщение отредактировал aiwa - Apr 20 2016, 10:09
Go to the top of the page
 
+Quote Post
Mty
сообщение Apr 20 2016, 11:33
Сообщение #28


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

Группа: Свой
Сообщений: 151
Регистрация: 19-12-04
Из: Москва
Пользователь №: 1 560



Спасибо, круто!

А вот интересно
register char* point=(char*)SP;
SP указывает на ПУСТУЮ ячейку или на ячейку с предыдущими данными?
Иными словами при PUSH сначала копируется данные, а потом инкрементируется SP или наоборот?

Сообщение отредактировал IgorKossak - Apr 20 2016, 17:21
Причина редактирования: бездумное цитирование
Go to the top of the page
 
+Quote Post
zltigo
сообщение Apr 20 2016, 12:34
Сообщение #29


Гуру
******

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



QUOTE (Mty @ Apr 20 2016, 14:33) *
Иными словами при PUSH сначала копируется данные, а потом инкрементируется SP или наоборот?

Все четыре варианта на выбор sm.gif F(full)D(descending)/FA(ascending)/E(empty)D/EA если ARM sm.gif
У AVR на вскидку не помню, но скорее на Empty указывает.



--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
aiwa
сообщение Apr 20 2016, 13:27
Сообщение #30


Местный
***

Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682



Цитата(Mty @ Apr 20 2016, 14:33) *
register char* point=(char*)SP;
SP указывает на ПУСТУЮ ячейку или на ячейку с предыдущими данными?

На пустую. Иначе бы затирался адрес возврата.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 10:20
Рейтинг@Mail.ru


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