?

Log in

No account? Create an account
 

Таинственное

About Уничтожить всех уродов

Previous Entry Таинственное 5 дек, 2011 @ 21:33 Next Entry
Дано:
1) микроконтроллер AT90CAN128
2) компилятор AVR GCC какой-то там из свежих.
3) код, выглядящий примерно так:
for (pid = pid.first; !pid.last; pid = pid.next)
{
  variable = get_some_data_from_peripheral(&pid);
  console_report(variable);
}


Всё прекрасно работает, причём уже давно и в разных устройствах.
Настал момент, когда пришлось взять старый дивайс (даже два) и заставить их делать то, к чему они не предполагались. Но, в общем, всё то же самое по сути. Теперь код выглядит так:
for (pid = pid.first; !pid.last; pid = pid.next)
{
  variable = get_some_data_from_peripheral(&pid);
  console_report(variable);
  CAN_transmit(TAG, variable);
}


Так вот, из-за добавления вызова функции, передающей по CAN значение интересующей меня переменной, (внимание!) вызов variable = get_some_data_from_peripheral(&pid); перестаёт возвращать корректные величины и начинает возвращать ахинею. И это не какой-нибудь там срыв стека - памяти ещё навалом, почти полтора килобайта. Мало того, если я делаю костыль типа:
for (pid = pid.first, id=0; !pid.last; pid = pid.next)
{
  variable[id] = get_some_data_from_peripheral(&pid);
  console_report(variable[id]);
  last_id = ++id;
}
/* bla-bla-bla */
for (id = 0; id != last_id; id++)
{
  CAN_transmit(TAG, variable);
}

то всё работает (разумеется, из-за этого приходится создавать массив variable[] с размером, точно заранее неизвестным (но можно прикинуть максимальную величину).

Это вообще КАК?! Каким образом вызов, осуществляемый сильно после, может влиять на вызов задолго до? Я бы ещё понял, если бы какая-то многопоточность-параллельность была, но это же строго однопоточная программа без ничего!
Оставить комментарий
[User Picture Icon]
From:metaclass
Date:Декабрь, 5, 2011 17:37 (UTC)
(Link)
Оно не "до", оно же в цикле. И явно CAN_transmit какие-нибудь регистры портит, например.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 17:39 (UTC)
(Link)
Неа, не портит. Мало того, get_some_data_from_peripheral педантично инициализирует всё, что ему нужно для работы.
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 17:48 (UTC)
(Link)
Может компилятор слишком умный и оптимизирует всё что можно и не можно?

Попробуй объявить variable как volatile.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 17:49 (UTC)
(Link)
Оптимизирует, конечно, но чтоб ТАК?!

А переменная и так стековая.
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 17:52 (UTC)
(Link)
"но чтоб ТАК" + "get_some_data_from_peripheral педантично инициализирует всё, что ему нужно для работы"

Вот инициализацию компилятор и мог выкинуть - если побочных эффектов не заметил. Поэтому объявляй нужные переменные volatile - это прямой запрет на оптимизацию.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 18:01 (UTC)
(Link)
в данном случае инициализируются хардварные регистры, а они так и так volatile. Это единственное, что могло бы порушиться, ибо каждый вызов get_some_data_from_peripheral ничего не знает о предыдущих.

Маловероятно, чтоб компилятор мог выкинуть переинициализацию железа.
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 18:03 (UTC)
(Link)
Значит надо объектный код смотреть. Если смотреть нечем, то попробуй у компилятора принудительно отключить оптимизацию -O0.

На крайняк доставай из архива предыдущую версию. :)
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 18:07 (UTC)
(Link)
да я уже так и сделал.. в общем, костыль работает - над его устранением подумаю, когда будет больше времени

Заодно провели замечательный эксперимент с однажды упоминавшейся коробочкой - на номинальной нагрузке с нашим мотором она работает примерно 30 секунд, после чего автоматически отключается из-за перегрева (датчики показывают температуру около 105 Ц). Хехе.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 18:02 (UTC)
(Link)
и самое главное - CAN_transmit НИКАК не может поломать variable, она ему передаётся через стек в виде копии. Это не указатель и не что-то такое.
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 18:09 (UTC)
(Link)
"CAN_transmit НИКАК не может поломать"

Может, если если есть ассемблерный вставки или еще какой неверный код. mov [%sp% - 100], x - и чужой стек порушен. Но это, конечно, уже фантастика.

Проще грешить на банальное переполнение буфера, если там есть буфера. Ну или console_report может иметь переполнение буфера и портить стек (если console_report, значит строки, а если строки на С - то прощай безопасность). А добавление CAN_transmit эту проблему как раз и вытащило наружу.
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 18:24 (UTC)
(Link)
Перепеши так:

for (pid = pid.first; !pid.last; pid = pid.next)
{
variable = get_some_data_from_peripheral(&pid);
CAN_transmit(TAG, variable);
console_report(variable);
}

Если и вправду переполнение, то поведение поменяется.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 19:04 (UTC)
(Link)
Пробовал, не меняется.
а console_report вылизан и отлажен пару лет назад - с тех пор юзаю без всяких нареканий
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 19:08 (UTC)
(Link)
А в репорте не просто строка, а байтовый фифо :)
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 17:50 (UTC)
(Link)
И если компилятор разворачивает цикл, то вызов get_some_data_from_peripheral идет ПОСЛЕ CAN_transmit
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 17:51 (UTC)
(Link)
не развернёт, т.к. список pid на этапе компиляции неизвестен - это не фиксированный перечень констант.
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 17:57 (UTC)
(Link)
В теории может и развернуть, если посчитает, что jump из тела дешевле перехода на условие. Компиляторы сейчас умные, переменная на стеке...

variable = get_some_data_from_peripheral(&pid);
console_report(variable);
CAN_transmit(TAG, variable);
*test pid.last*
*jz наружу*
variable = get_some_data_from_peripheral(&pid);
console_report(variable);
CAN_transmit(TAG, variable);
*test pid.last*
*jz наружу*
...
goto в начало.

Но это теория. Практически же надо смотреть объекный код, если есть чем.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 18:05 (UTC)
(Link)
а как он узнает длину списка-то? сколько ему раз надо нагенерить? список-то создаётся после запуска программы, когда она пересчитает периферию (а её количество изначально неизвестно и может быть, например, нулевым)
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 19:05 (UTC)
(Link)
да ну нафиг, как можно развернуть то, что может запросто оказаться бесконечным?
[User Picture Icon]
From:oppositus
Date:Декабрь, 5, 2011 18:01 (UTC)
(Link)
Ну и CAN_transmit может чужой стек портить, если там указатели не туда смотрят.

А по поводу предыдущего - volatile надо объявить и variable и pid.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 18:03 (UTC)
(Link)
все pid берутся из списка правильно, я это первым делом проверил.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 18:08 (UTC)
(Link)
волатилов у меня везде понатыкано.. и в большинстве функций переменные отдаются как const.
From:kotenstein
Date:Декабрь, 5, 2011 18:59 (UTC)
(Link)
ха, это ж микроконтроллеры.
у меня на меге 128 в одной программе на ровном месте портился указатель на стек данных.
заменил чип — эффект пропал, как не было.
[User Picture Icon]
From:kincajou
Date:Декабрь, 5, 2011 19:06 (UTC)
(Link)
прошил другую прошивку - глюк пропал. Прошил эту - появился. Дело в каком-то затыке компилятора.

И это не срыв стека.
[User Picture Icon]
From:aterentiev
Date:Декабрь, 5, 2011 20:23 (UTC)
(Link)
Может сгенери асм-код и посмотри разницу с вызовом can_transmit и без
[User Picture Icon]
From:dev_zzo
Date:Декабрь, 6, 2011 08:51 (UTC)
(Link)
И всё же дизассемблерный дамп этого участка кода в студию. А там и будем смотреть.
[User Picture Icon]
From:kincajou
Date:Декабрь, 6, 2011 16:13 (UTC)
(Link)
он БОЛЬШОЙ. То, что я написал - верхушка.

Скопировал странный кусок в код совсем другой программы другой железяки, но тоже на AVR (только на другой AVR ;)) - работает.
(Оставить комментарий)
Top of Page Разработано LiveJournal.com