Неверное поведение кода при включении функций (возможное ограничение размера)

Я понимаю, что эта тема довольно расплывчата.... поэтому я попытаюсь объяснить это.

Я работаю над проектом в IAR Workbench. Я дошел до того, что если я добавлю новую функцию, такую ​​как простой оператор if, вся структура кода сломается. Код нормально компилируется и загружается на устройство 8051, но в середине последовательности запуска кода я теряю связь. Как будто происходит переполнение стека. Если я приостанавливаю отладчик, я вижу, что мои значения XdataStack и IdataStack низкие (менее 50%) и нет переполнений стека, о которых нужно сообщить.

На самом деле код, вызывающий проблему, даже не вызывается приложением.

Это станет еще более очевидным, если я включу константу отладки #define, которая есть в моем коде. Включение этого параметра приводит к тому, что в код для отладки uart встраивается больше строковых констант.

Еще один тест, который я выполнил, заключался в создании массива из 100 символов в уже существующей функции.

char hello[100];
memset(hello, 0x00, 100);

И это также, кажется, нарушает код.

Мне было интересно, есть ли области памяти, на которые я должен посмотреть, возможно, я заполнил это устройство (CC2540 с размером флэш-памяти 128 КБ)

IAR позволяет мне изучить:

  • IDATA
  • ХДАННЫЕ
  • СФР
  • Логический код
  • Код
  • Данные
  • пданные

Что касается конфигурации моего проекта:

Размеры стека:

  • ИДАННЫЕ: 0xC0
  • КПД: 0x00
  • ХДАННЫЕ: 0x280

Размеры кучи:

  • ХДАННЫЕ: 0xFF
  • Далеко: 0xFFF
  • Far22: 0xFFF Огромный: 0xFFF

person Jonathan    schedule 27.11.2012    source источник
comment
К сожалению, это тип вопроса, который плохо работает на SO. Предлагаемый следующий шаг: попробуйте вызвать это поведение с помощью минимального примера (неуклонно увеличивая площадь пустого приложения) — видите ли вы те же симптомы, когда пересекаете порог? Соответствует ли этот порог размеру флэш-памяти?   -  person Brian Cain    schedule 27.11.2012
comment
Я ожидал этого. Прежде чем задать этот вопрос, я сделал то, о чем вы говорили. Я неуклонно увеличивал след, пока не нашел порог. Я полагаю, что недостаточно разбираюсь в IAR Workbench, чтобы внимательно следить за размером стека/кучи/кода   -  person Jonathan    schedule 27.11.2012
comment
Я неуклонно увеличивал площадь... ...минимального примера? пока не нашел порог... ...и что потом?   -  person Brian Cain    schedule 27.11.2012
comment
Таким образом, исходный проект был построен на примере поставки от TI. Я добавил функциональность, как обсуждалось, и дошел до того, что эта проблема проявляется. Я немного смущен тем, как сообщается размер XDATA. Я вызываю функцию, которая создает строку локальной переменной размером 100, и размер памяти XDATA резко возрастает. Но когда функция завершается, индикатор памяти не возвращается к исходным уровням. Не будет ли строковая переменная выталкиваться из стека и сбрасываться?   -  person Jonathan    schedule 28.11.2012
comment
Я вижу это, когда сторожевой таймер включен при загрузке, например. на более крупных устройствах Silabs 8051Fxxx, поскольку заполнение XDATA занимает больше времени, чем время ожидания сторожевого таймера. TI CC2540, похоже, не включает его по умолчанию, если я правильно прочитал руководство.   -  person Turbo J    schedule 08.12.2012


Ответы (1)


Как будто происходит переполнение стека.

Это довольно маловероятно для 8051, потому что стек используется не очень интенсивно. Без эффективных режимов косвенной адресации он в основном ограничивается хранением обратных адресов (автоматически управляемых MCU) и сохраненными регистрами (в основном в ISR).

Еще один тест, который я выполнил, заключался в создании массива из 100 символов в уже существующей функции [...] И это также, похоже, нарушает код.

Ваш код в основном эквивалентен: f() { static char hello[100]; ... } с компилятором, управляющим всеми этими "локальными" переменными с наложениями, так что эти 100 байтов безопасны для использования только при выполнении f(). Это может работать только в том случае, если компилятор может сказать, какие функции могут быть вызваны во время выполнения f(). Если компилятор проанализировал дерево вызовов неправильно, это приведет к тому, что локальные переменные (включая аргументы функций, принимающих слишком много аргументов для передачи в регистры) будут перезаписаны неожиданным образом.

Компилятор должен быть достаточно умен, чтобы рассматривать main() и все ваши ISR как корни независимых деревьев вызовов. Его легко обмануть вычисляемыми переходами, вызовами через указатели функций и такими понятиями, как «задачи» в RTOS. Например, если вы используете указатели функций, вам придется сообщить компилятору (вероятно, в качестве опции компоновщика) все функции, которые могут быть вызваны из функции, вызываемой через указатель.

person Ben Jackson    schedule 24.02.2014