ashr 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Столкнулся с такой проблемой. Перестает работать printf (а также sprintf, vprintf и т.д.), если запущена ОСь. Проявляется это в том, что функция неправильно вынимает из стека, переданные ей параметры и, соответственно, неправильно их выводит. Эффект наблюдается только на CortexM3 с компилятором IAR (конкретно 5.41.2). На ARM7, BlackFin, AVR, MSP430 - не наблюдается. В чем может быть причина этого и как с это исправить? Факты к размышлению. 1. У Cortexa есть два стека (в отличии от других упомянутых процев). Причем тот, который привычный CSTACK используется для прерываний. Для нужд приложения используется второй стек. 2. В связке CortexM3 + GCC printf сначала не работал, но после выравнивания стека задач TStackItem Stack[] на границу 8 байт, функция заработала. Выравнивание при использовании IAR не помогло. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба 2. В связке CortexM3 + GCC printf сначала не работал, но после выравнивания стека задач TStackItem Stack[] на границу 8 байт, функция заработала. Выравнивание при использовании IAR не помогло. Вот что я нарыл по этому поводу: 8 byte stack alignment is a requirement of the ARM Architecture Procedure Call Standard [AAPCS]. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ashr 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Вот что я нарыл по этому поводу: 8 byte stack alignment is a requirement of the ARM Architecture Procedure Call Standard [AAPCS]. Да, проблема именно в выравнивании стека задачи. Сейчас на свежую голову выполнил выравнивание и все заработало. В прошлый раз по запарке не тем средством для выравнивания воспользовался. Вопрос снят. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Вопрос снят. А как это выглядит в IAR-е? (Как задаётся выравнивание?) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Да, проблема именно в выравнивании стека задачи. Сейчас на свежую голову выполнил выравнивание и все заработало. Хм, у меня тоже проект в ИАРе. Никакого выравнивания не делал, всё работает. Правда, printf() не пользуюсь, только vsnprintf(). А сама операционка разве не делает выравнивание стеков задач? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Никакого выравнивания не делал, всё работает. Там как повезёт. Добавил переменную - работает, убавил - не работает:) А сама операционка разве не делает выравнивание стеков задач? Пока не делает, починяем:) В качестве временной меры надо в OS_Kernel.h сделать так: __attribute__ ((aligned (8))) TStackItem Stack[stack_size/sizeof(TStackItem)]; (не знаю как в IAR задаётся выравнивание) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ashr 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба А как это выглядит в IAR-е? (Как задаётся выравнивание?) Сейчас временно сделал так. При определении объекта задачи: #pragma data_alignment=8 Some_task task_obj; Но это не совсем правильно. В scmRTOS, как мне думается, выравнивание надо делать как-то вроде этого (не помню как это называется): class process : public TBaseProcess { ... private: union Align_buff { long long dummy; TStackItem Stack[stack_size/sizeof(TStackItem)]; }; Align_buff buff; }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Там как повезёт. Добавил переменную - работает, убавил - не работает:) Ну, тогда, наверное, мне сильно везёт, так как вывода через vsnprintf() много и самого разного. Кстати, мне вот не особо понятно, как применительно к стеку может относится выравнивание в 8 байт? Ведь минимальная величина изменения указателя стека - 4 байта, не 8? Тогда получается выравнивать надо по границе слова, а не двух слов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ashr 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Ну, тогда, наверное, мне сильно везёт, так как вывода через vsnprintf() много и самого разного. Дело не в количестве вывода через printf. Вам везет, что стек выровнен как надо. Кстати какой проц. Не факт, что вам требуется выравнивание именно на 8 байт. Кстати, мне вот не особо понятно, как применительно к стеку может относится выравнивание в 8 байт? Требование конторы ARM, ссылка уже была. И у IARa в Development Guide для ARM Cores четко прописано 8 байтное выравнивание стека. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба #pragma data_alignment=8 Some_task task_obj; То есть, выравнивание стека задать таким образом нельзя, только выравнивание всего объекта? Это конечно не дело. Ну, тогда, наверное, мне сильно везёт, так как вывода через vsnprintf() много и самого разного. Или IAR у вас старый, и ещё не научился пользоваться новыми фишками:) Кстати, мне вот не особо понятно, как применительно к стеку может относится выравнивание в 8 байт? Мне тоже не очень понятно. Но - стандарт, что поделать. Тем более, что имеем явный пример глюков, которые можно получить, не соблюдая этот стандарт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Дело не в количестве вывода через printf. Вам везет, что стек выровнен как надо. Кстати какой проц. Не факт, что вам требуется выравнивание именно на 8 байт. У меня LPC1768. В теме, по моему, ясно написано Cortex-M3. Неужели двум чипам на одном и том же ядре требуется разное выравнивание? У себя использую три процесса с такими стеками: typedef OS::process<OS::pr1, 500> TProc1; typedef OS::process<OS::pr2, 800> TProc2; typedef OS::process<OS::pr3, 500> TProc3; Посмотрел в map файле линкера их расположение: Proc1 0x10001ee8 0x200 Data Gb main.o [1] Proc2 0x100020e8 0x32c Data Gb main.o [1] Proc3 0x10002414 0x200 Data Gb main.o [1] Как видно, стек третьего процесса не выровнен по границе 8 байт. Однако же именно этот низкоприоритетный поток постоянно юзает печать через vsnprintf(). Вот и не верится мне что-то, что ваша проблема на 100% связана с выравниванием. Или IAR у вас старый, и ещё не научился пользоваться новыми фишками:) EWARM v5.50.5. Поновее, чем у автора. Может, наоборот, старенький ИАР подглючивает? ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Как видно, стек третьего процесса не выровнен по границе 8 байт. Однако же именно этот низкоприоритетный поток постоянно юзает печать через vsnprintf(). Возможно, проблема не гарантировано появляется, а лишь с какой-то вероятностью. Или стек расположен не в начале объекта TBaseProcess, и как раз наоборот, получается выровненным. Не знаю. Попробуйте ещё добавлять/убавлять переменные, чтобы выравнивание изменилось и возможно поймаете этот глюк. Вот и не верится мне что-то, что ваша проблема на 100% связана с выравниванием. Если ничего не меняя, только выравнивание, удаётся решить проблему, то вероятнее всего, что проблема именно в выравнивании, не правда ли? :) Может, наоборот, старенький ИАР подглючивает? ;) Дело в том, что и на GCC та же проблема (см. первое сообщение топика, п. 2) (это как раз я проверял, с GCC). ЗЫ. Дополню картину. В проекте вызываю тестовую функцию дважды - один раз до вызова OS:Run(), второй - после, уже из процесса. В первом случае результат корректный, во втором - нет. Запрет прерываний во втором случае не спасает. Зато выравнивание стека процесса - устраняет глюк. Какие тут можно придумать варианты, кроме стека? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Возможно, проблема не гарантировано появляется, а лишь с какой-то вероятностью. Или стек расположен не в начале объекта TBaseProcess, и как раз наоборот, получается выровненным. Не знаю. Да, резервируется место, на 12 байт большее отведённого места под стек. Для чего, интересно? ЗЫ. Дополню картину. В проекте вызываю тестовую функцию дважды - один раз до вызова OS:Run(), второй - после, уже из процесса. В первом случае результат корректный, во втором - нет. Запрет прерываний во втором случае не спасает. Зато выравнивание стека процесса - устраняет глюк. Какие тут можно придумать варианты, кроме стека? Было бы неплохо для наглядности продебажить на самом низком уровне и увидеть, в каком именно месте затык. Ведь даже если вершина стека является выровненной до 8 байт, разве не может на момент вызова любой функции текущий адрес стека быть равен его вершине-4, -12 и т.д. с кратностью 4? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Да, резервируется место, на 12 байт большее отведённого места под стек. Для чего, интересно? Как это для чего? Вот же: class TBaseProcess { ... protected: TStackItem* StackPointer; TTimeout Timeout; TPriority Priority; }; Вот они, наши 12 байт. Итого, 0x10002414 + 12 = 0x10002420 (!) Вот потому и работает printf :) Ведь даже если вершина стека является выровненной до 8 байт, разве не может на момент вызова любой функции текущий адрес стека быть равен его вершине-4, -12 и т.д. с кратностью 4? Нет. Компилятор обеспечивает дискретность выделения стека, равную восьми байтам. Таким образом получается, что при условии изначального выравнивания стека на границу 8 байт, оно соблюдается (сохраняется) при любом уровне вложенности вызовов. (ИМХО конечно) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 7 февраля, 2011 Опубликовано 7 февраля, 2011 · Жалоба Как это для чего? Вот же: А, точно, вот они где :) Итого, 0x10002414 + 12 = 0x10002420 (!) Вот потому и работает printf :) Э, нет, Антоха, так просто не получится - посмотри на другие два процесса - они тоже печатью занимаются :) Там выравнивание тогда будет нарушаться. Нет. Компилятор обеспечивает дискретность выделения стека, равную восьми байтам. Таким образом получается, что при условии изначального выравнивания стека на границу 8 байт, оно соблюдается (сохраняется) при любом уровне вложенности вызовов. (ИМХО конечно) Ну если компилер поддерживает выравнивание - тогда всё в порядке. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться