Перейти к содержанию
    

Столкнулся с такой проблемой.

Перестает работать printf (а также sprintf, vprintf и т.д.), если запущена ОСь. Проявляется это в том, что функция неправильно вынимает из стека, переданные ей параметры и, соответственно, неправильно их выводит.

Эффект наблюдается только на CortexM3 с компилятором IAR (конкретно 5.41.2). На ARM7, BlackFin, AVR, MSP430 - не наблюдается.

В чем может быть причина этого и как с это исправить?

 

Факты к размышлению.

1. У Cortexa есть два стека (в отличии от других упомянутых процев). Причем тот, который привычный CSTACK используется для прерываний. Для нужд приложения используется второй стек.

2. В связке CortexM3 + GCC printf сначала не работал, но после выравнивания стека задач TStackItem Stack[] на границу 8 байт, функция заработала. Выравнивание при использовании IAR не помогло.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2. В связке CortexM3 + GCC printf сначала не работал, но после выравнивания стека задач TStackItem Stack[] на границу 8 байт, функция заработала. Выравнивание при использовании IAR не помогло.

Вот что я нарыл по этому поводу: 8 byte stack alignment is a requirement of the ARM Architecture Procedure Call Standard [AAPCS].

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, проблема именно в выравнивании стека задачи.

Сейчас на свежую голову выполнил выравнивание и все заработало.

В прошлый раз по запарке не тем средством для выравнивания воспользовался.

 

Вопрос снят.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, проблема именно в выравнивании стека задачи.

Сейчас на свежую голову выполнил выравнивание и все заработало.

Хм, у меня тоже проект в ИАРе.

Никакого выравнивания не делал, всё работает.

Правда, printf() не пользуюсь, только vsnprintf().

 

А сама операционка разве не делает выравнивание стеков задач?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Никакого выравнивания не делал, всё работает.

Там как повезёт. Добавил переменную - работает, убавил - не работает:)

А сама операционка разве не делает выравнивание стеков задач?

Пока не делает, починяем:)

В качестве временной меры надо в OS_Kernel.h сделать так:

     __attribute__ ((aligned (8))) TStackItem Stack[stack_size/sizeof(TStackItem)];

(не знаю как в IAR задаётся выравнивание)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А как это выглядит в 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;
};

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там как повезёт. Добавил переменную - работает, убавил - не работает:)

Ну, тогда, наверное, мне сильно везёт, так как вывода через vsnprintf() много и самого разного.

 

Кстати, мне вот не особо понятно, как применительно к стеку может относится выравнивание в 8 байт?

Ведь минимальная величина изменения указателя стека - 4 байта, не 8?

Тогда получается выравнивать надо по границе слова, а не двух слов?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, тогда, наверное, мне сильно везёт, так как вывода через vsnprintf() много и самого разного.

Дело не в количестве вывода через printf. Вам везет, что стек выровнен как надо. Кстати какой проц. Не факт, что вам требуется выравнивание именно на 8 байт.

 

 

Кстати, мне вот не особо понятно, как применительно к стеку может относится выравнивание в 8 байт?

Требование конторы ARM, ссылка уже была. И у IARa в Development Guide для ARM Cores четко прописано 8 байтное выравнивание стека.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#pragma data_alignment=8
Some_task task_obj;

То есть, выравнивание стека задать таким образом нельзя, только выравнивание всего объекта? Это конечно не дело.

 

Ну, тогда, наверное, мне сильно везёт, так как вывода через vsnprintf() много и самого разного.

Или IAR у вас старый, и ещё не научился пользоваться новыми фишками:)

 

Кстати, мне вот не особо понятно, как применительно к стеку может относится выравнивание в 8 байт?

Мне тоже не очень понятно. Но - стандарт, что поделать. Тем более, что имеем явный пример глюков, которые можно получить, не соблюдая этот стандарт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дело не в количестве вывода через 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.

Поновее, чем у автора.

Может, наоборот, старенький ИАР подглючивает? ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как видно, стек третьего процесса не выровнен по границе 8 байт.

Однако же именно этот низкоприоритетный поток постоянно юзает печать через vsnprintf().

Возможно, проблема не гарантировано появляется, а лишь с какой-то вероятностью. Или стек расположен не в начале объекта TBaseProcess, и как раз наоборот, получается выровненным. Не знаю. Попробуйте ещё добавлять/убавлять переменные, чтобы выравнивание изменилось и возможно поймаете этот глюк.

Вот и не верится мне что-то, что ваша проблема на 100% связана с выравниванием.

Если ничего не меняя, только выравнивание, удаётся решить проблему, то вероятнее всего, что проблема именно в выравнивании, не правда ли? :)

Может, наоборот, старенький ИАР подглючивает? ;)

Дело в том, что и на GCC та же проблема (см. первое сообщение топика, п. 2) (это как раз я проверял, с GCC).

 

ЗЫ. Дополню картину. В проекте вызываю тестовую функцию дважды - один раз до вызова OS:Run(), второй - после, уже из процесса.

В первом случае результат корректный, во втором - нет. Запрет прерываний во втором случае не спасает. Зато выравнивание стека процесса - устраняет глюк. Какие тут можно придумать варианты, кроме стека?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно, проблема не гарантировано появляется, а лишь с какой-то вероятностью. Или стек расположен не в начале объекта TBaseProcess, и как раз наоборот, получается выровненным. Не знаю.

Да, резервируется место, на 12 байт большее отведённого места под стек.

Для чего, интересно?

ЗЫ. Дополню картину. В проекте вызываю тестовую функцию дважды - один раз до вызова OS:Run(), второй - после, уже из процесса.

В первом случае результат корректный, во втором - нет. Запрет прерываний во втором случае не спасает. Зато выравнивание стека процесса - устраняет глюк. Какие тут можно придумать варианты, кроме стека?

Было бы неплохо для наглядности продебажить на самом низком уровне и увидеть, в каком именно месте затык.

 

Ведь даже если вершина стека является выровненной до 8 байт, разве не может на момент вызова любой функции текущий адрес стека быть равен его вершине-4, -12 и т.д. с кратностью 4?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, резервируется место, на 12 байт большее отведённого места под стек.

Для чего, интересно?

Как это для чего? Вот же:

    class TBaseProcess
    {
...
    protected:
        TStackItem* StackPointer;
        TTimeout Timeout;
        TPriority Priority;
    };

Вот они, наши 12 байт. Итого, 0x10002414 + 12 = 0x10002420 (!) Вот потому и работает printf :)

 

Ведь даже если вершина стека является выровненной до 8 байт, разве не может на момент вызова любой функции текущий адрес стека быть равен его вершине-4, -12 и т.д. с кратностью 4?

Нет. Компилятор обеспечивает дискретность выделения стека, равную восьми байтам. Таким образом получается, что при условии изначального выравнивания стека на границу 8 байт, оно соблюдается (сохраняется) при любом уровне вложенности вызовов.

(ИМХО конечно)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как это для чего? Вот же:

А, точно, вот они где :)

Итого, 0x10002414 + 12 = 0x10002420 (!) Вот потому и работает printf :)

Э, нет, Антоха, так просто не получится - посмотри на другие два процесса - они тоже печатью занимаются :)

Там выравнивание тогда будет нарушаться.

Нет. Компилятор обеспечивает дискретность выделения стека, равную восьми байтам. Таким образом получается, что при условии изначального выравнивания стека на границу 8 байт, оно соблюдается (сохраняется) при любом уровне вложенности вызовов.

(ИМХО конечно)

Ну если компилер поддерживает выравнивание - тогда всё в порядке.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...