|
|
  |
WinAVR-20071221 и AVR Studio 4.13 SP2 Final, новые релизы программ |
|
|
|
Dec 21 2007, 19:35
|
Частый гость
 
Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977

|
WinAVR-20071221 hxxp://sourceforge.net/project/showfiles.php?group_id=68108 Что нового: - Added support for these devices: AT90PWM216, AT90PWM316, ATtiny43U, ATtiny48, ATtiny88, AT90PWM2B, AT90PWM3B, ATmega48P, ATmega88P, ATmega168P, ATmega328P, ATmega1284P, ATmega32HVB
- Binutils 2.18 - New version.
- GCC 4.2.2 - New version.
- avr-libc 1.6.0 - New version.
- avrdude 5.5 - New version.
- GDB / Insight 6.6 - New version.
- AVaRICE 2.7 - New version.
- SRecord 1.37 - New version.
AVR Studio 4.13 SP2(b571) hxxp://www.atmel.com/dyn/resources/prod_documents/AVRStudio4.13SP2.exe - ATmega32HVB, ATmega1284P, ATtiny48, ATtiny43U.
- Full support for the new STK600 starter kit, including programming front-end and command line tools.
- New devices in Simulator V2: ATmega164P, ATmega324P, ATmega644P, ATmega1284P, ATmega48P, ATmega88P, ATmega168P, ATmega328P, ATmega32HVB, ATtiny48 and ATtiny43U.
- ELF production file format support.
- Several enhancements in the IO view.
- and many more...
|
|
|
|
|
Dec 22 2007, 08:27
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(aesok @ Dec 21 2007, 23:07)  Функция с атрибутом 'OS_task' не сохраняет "call-saved" регистры (r2-r15, r28-r29 ), Как этот атрибут соотносится с __noreturn__ ? В смысле в чём отличие? Я в avr-gcc порте scmRTOS для OS_PROCESS и для OS::Run() просто дал атрибут __noretrun__ и вроде бы всё нормально. Регистры не сохраняются, стек даром не расходуется. Заодно проверка компилятором - сообщение об ощибке, если вдруг нечаянно устроил возврат из главной функции процесса, по кр. мере в scmRTOS это делать нельзя и дополнительная помощь со стороны компилятора не помешает.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Dec 22 2007, 10:32
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(haker_fox @ Dec 22 2007, 03:55)  Судя по дате, продукт недавний. Как у него на счет стабильности? Т.е. если я использую, например scmRTOS, то все функции-процессы можно объявлять с атрибутом OS_task? Скорее всего да, но я не работал с scmRTOS, а глянув на исходники не нашeл там порта на GCC. общее правило такое, если код вызывающий функцию-процесс не расчитывает на то что регистры r2-r15, r28-r29 сохранят свое значение после возврата из этой функции, то эту функция можно объявлять с атрибутом 'OS_task'.
Сообщение отредактировал aesok - Dec 22 2007, 10:32
|
|
|
|
|
Dec 22 2007, 12:00
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(aesok @ Dec 22 2007, 12:32)  Скорее всего да, но я не работал с scmRTOS, а глянув на исходники не нашeл там порта на GCC. Он там пока в репозитории в branches/avreal лежит. Нужно ещё очень внимательно проверить. Но пользоваться уже можно. Да её и раньше портировали "частным порядком", там немного работы. Цитата общее правило такое, если код вызывающий функцию-процесс не расчитывает на то что регистры r2-r15, r28-r29 сохранят свое значение после возврата из этой функции, то эту функция можно объявлять с атрибутом 'OS_task'. И всё же как по моему вопросу - соотношению атрибутов OS_task и noreturn ? Правильно ли я понимаю, что OS_task это старый добрый noreturn минус подавление генерации команды ret и проверка компилятором построения функции как действительно никогад не возвращающей управления? Похоже, что для процессов scmRTOS правильнее применять noreturn, а OS_task оставить для тех ОС, в которых процесс может прекратить существование путём возврата из основной функции процесса.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Dec 22 2007, 12:25
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(ReAl @ Dec 22 2007, 15:00)  И всё же как по моему вопросу - соотношению атрибутов OS_task и noreturn ?
Правильно ли я понимаю, что OS_task это старый добрый noreturn минус подавление генерации команды ret и проверка компилятором построения функции как действительно никогад не возвращающей управления? Я перичитал описание атрибута 'noreturn' - основное его предназначение позволить компилятору оптимизировать вызывающию функцию, и не генерировать в ней код после вызова функции с атрибутом 'noreturn'. Как компилятор должен/может оптимизировать саму функцию к которой применен атрибут 'noreturn' надо посмотреть. Атрибут "OS_task" (OS_main) заставляет компилятор генерировать специальные версии пролога и эпилога для указанной функции. Эта функция перестает соответствовать соглашениям о вызове функций в С, и не должна вызываться из С кода. Цитата Похоже, что для процессов scmRTOS правильнее применять noreturn, а OS_task оставить для тех ОС, в которых процесс может прекратить существование путём возврата из основной функции процесса. 'noreturn' ничего не даст кроме предупреждения компилятора, если функция функция всетаки возвращает управление. Компилятор не сможет оптимизировать вызывающий код, он же написан в ассемблере. Для функции с OS_task генерируються более эффективные пролог и эпилог, если функция не не возвращается, то эпилог не генерируеться. Анатолий. PS: Для тех кто не знаком с терминами пролог и эпилог: пролог - код выполняемый до начала тала функции, сохраняет 'call-saved' реистры и выделяет место в стеке для локальных переменных. эпилог - код выполняемый после тала функции, востанавливает 'call-saved' реистры, освобождает место в стеке выделеное в прологе и выполняет команду 'RET'. Анатолий.
Сообщение отредактировал aesok - Dec 22 2007, 13:09
|
|
|
|
|
Dec 22 2007, 20:05
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(aesok @ Dec 22 2007, 15:25)  Цитата И всё же как по моему вопросу - соотношению атрибутов OS_task и noreturn ? Правильно ли я понимаю, что OS_task это старый добрый noreturn минус подавление генерации > команды ret и проверка компилятором построения функции как действительно никогад не возвращающей управления?
Я перичитал описание атрибута 'noreturn' - основное его предназначение позволить компилятору оптимизировать вызывающию функцию, и не генерировать в ней код после вызова функции с атрибутом 'noreturn'. Как компилятор должен/может оптимизировать саму функцию к которой применен атрибут 'noreturn' надо посмотреть. Разница между "noreturn' и 'OS_task' есть: первый предотвращает сохранение регстров r2-r15, второй дополнительно r28-r29. Ну и само сабой 'OS_task' работает для всех функций, вне зависимости от того возвращают они управление или нет. Анатолий.
|
|
|
|
|
Dec 23 2007, 07:13
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(aesok @ Dec 22 2007, 14:25)  'noreturn' ничего не даст кроме предупреждения компилятора, если функция функция всетаки возвращает управление. Ну и на том спасибо :-), я стараюсь, чтобы предупреждений не было вообще и при таком подходе даже просто выдать предупреждение - уже помощь компилятора. Цитата(aesok @ Dec 22 2007, 22:05)  Разница между "noreturn' и 'OS_task' есть: первый предотвращает сохранение регстров r2-r15, второй дополнительно r28-r29. Ну и само сабой 'OS_task' работает для всех функций, вне зависимости от того возвращают они управление или нет. Я немного поэкспериментировал, для avr-gcc 4.2.2 (WinAVR-20071221) для функции, помеченной этими атрибутами, различие действительно такое (для noreturn добавляется сохранение r28,r29 в начале пролога, если же организовать возврат из функции, то и в конце эпилога) а вот 4.3.0 (сборка klen http://electronix.ru/forum/index.php?showtopic=38876) генерирует абсолютно одинаковый код для этих двух атрибутов (видать какой-то патч с winavr.cvs.sourceforge... недотащен был). Более ранние компиляторы, естетсвенно, вообще OS_task не знают. Так что я пока оставлю как есть, с noreturn, а там посмотрим, добавлю проверку версии компилятора и в зависимости от этого изменение #define OS_PROCESS на атрибут noreturn или OS_task. Цитата(Сергей Борщ @ Dec 23 2007, 00:57)  Есть еще вопрос по "noreturn" с main() в режиме С++. Как известно, main() в С++ должна быть объявлена как возвращающая int. Если к ней добавить "noreturn", то появляется warning: main.cpp:68: warning: function declared 'noreturn' has a 'return' statement хотя никаких return statement в функции нет, из for(;;) {} выхода тоже не сущствует, и никаких ret в листинге нет. Это бага? return 0; перед закрывающей скобкой '}' в main() в С++ присутствует неявно, если его не написал программист. В стандарте написано: Цитата 3.6.1 Main function ... 5 A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the effect is that of executing return 0; А в "полновесном" С++ управление на закрывающую скобку main() может перейти и при бесконечном цикле, и при noreturn-функции (о которых стандарт вообще ничего не знает) - за счёт исключения. Поэтому return 0; всегда неявно присутствует для С++ - программы. Есть ли смысл делать в avr-gcc какой-то особый подход - я не уверен. Да, он всё равно не поддерживает исключения и за бесконечный цикл в main() не попасть никак, но "генерация" неявного retrun 0; и упомянутого предупреждения происходит, как я понимаю, на платформо-независимых этапах компиялции. А потом оптимизатор выбрасывает это как unreachable code, но это потом :-)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Dec 23 2007, 10:37
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(ReAl @ Dec 23 2007, 09:13)  но "генерация" неявного retrun 0; и упомянутого предупреждения происходит, как я понимаю, на платформо-независимых этапах компиялции. А потом оптимизатор выбрасывает это как unreachable code, но это потом :-) Я понятия не имею, как оно работает внутри  . Я снаружи лишь вижу warning, лезу в листинг и не нахожу там никакого ret на который выдано предупреждение. Это несколько, хм... смущает.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 23 2007, 20:02
|
Участник

Группа: Участник
Сообщений: 34
Регистрация: 27-05-05
Из: Rivne, Ukraine
Пользователь №: 5 472

|
Нормально скачалось.
|
|
|
|
|
Dec 24 2007, 09:25
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(ReAl @ Dec 23 2007, 10:13)  Более ранние компиляторы, естетсвенно, вообще OS_task не знают. Так что я пока оставлю как есть, с noreturn, а там посмотрим, добавлю проверку версии компилятора и в зависимости от этого изменение #define OS_PROCESS на атрибут noreturn или OS_task. Используйте оба этих атрибута: 'noreturn' - для генерации предупреждений а "OS_task" для экономии кода и стека. Анатолий.
|
|
|
|
|
Dec 24 2007, 21:39
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(733259 @ Dec 24 2007, 21:49)  А чем OS_main отличается от __attribute__((naked))? Всегда применяю для main и никаких warning-ов и лишнего кода. Дело в том что атрибут 'naked' выкидывает не только лишний но и нужный код. Анатолий.
|
|
|
|
|
Dec 25 2007, 04:29
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата(aesok @ Dec 25 2007, 02:39)  Дело в том что атрибут 'naked' выкидывает не только лишний но и нужный код. Выкидывает, но только не в main - там пролог и эпилог не нужны.
|
|
|
|
|
Dec 25 2007, 05:36
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(733259 @ Dec 25 2007, 07:29)  Выкидывает, но только не в main - там пролог и эпилог не нужны. Я вот тоже попробовал naked, и прошло нормально. Но в мэйне не должно быть локальных переменных.
|
|
|
|
|
Dec 25 2007, 05:48
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Я вот тоже попробовал naked, и прошло нормально. Но в мэйне не должно быть локальных переменных. А можно подробнее? У меня постоянно в main локальные переменные, обычно static правда, хотя точно не уверен т.к. int main() __attribute__((naked)); int main(){ у меня вооще везде, стереотип выработался.
|
|
|
|
|
Dec 25 2007, 05:58
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(733259 @ Dec 25 2007, 08:48)  А можно подробнее? У меня постоянно в main локальные переменные, обычно static правда, хотя точно не уверен т.к.
int main() __attribute__((naked)); int main(){
у меня вооще везде, стереотип выработался. static - не локальная!! Это глобальная переменная с ограниченной областью видимости.
|
|
|
|
|
Dec 25 2007, 06:13
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата(Qwertty @ Dec 25 2007, 10:58)  static - не локальная!! Это глобальная переменная с ограниченной областью видимости. Это я знаю, какие траблы с локальными переменными main? Я не заметил никаких, вот и спрашиваю.
|
|
|
|
|
Dec 25 2007, 06:18
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(733259 @ Dec 25 2007, 09:13)  Это я знаю, какие траблы с локальными переменными main? Я не заметил никаких, вот и спрашиваю. Так они в прологе создаются и инициализируются. А naked пролог выкидывает
|
|
|
|
|
Dec 25 2007, 07:09
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Согласен, только чем отличается переменная static от локальной в main, ведь эта, локальная, всё равно всегда существует вместе с main.
ЗЫ: скачал, под wine работает безупречно. Не заметил разницы между naked и OS_main на примере, специально объявил uint16_t array[64] в main. Бинарник совпадает до байта. К сожалению реальный код, как и в предыдущих версиях, больше чем у 3.3.6, 3660 байт против 3274 в одном из моих проектов. Жаль.
|
|
|
|
|
Dec 25 2007, 09:39
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(733259 @ Dec 25 2007, 10:09)  Согласен, только чем отличается переменная static от локальной в main, ведь эта, локальная, всё равно всегда существует вместе с main. Различие в том, где она создается. Локальная - в прологе мэйна. Static - в секции bss, если не ошибаюсь. Цитата(733259 @ Dec 25 2007, 10:09)  ЗЫ: скачал, под wine работает безупречно. Не заметил разницы между naked и OS_main на примере, специально объявил uint16_t array[64] в main. Бинарник совпадает до байта. К сожалению реальный код, как и в предыдущих версиях, больше чем у 3.3.6, 3660 байт против 3274 в одном из моих проектов. Жаль. А массивы вроде локальными не бывают, они всегда static, даже если объявлены локальными. Это сразу видно по использованию ОЗУ, массив сразу увеличивает использованное ОЗУ, а простые локальные переменные не увеличивают.
|
|
|
|
|
Dec 25 2007, 10:04
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(733259 @ Dec 25 2007, 10:09)  ЗЫ: скачал, под wine работает безупречно. Не заметил разницы между naked и OS_main на примере, специально объявил uint16_t array[64] в main. Бинарник совпадает до байта. К сожалению реальный код, как и в предыдущих версиях, больше чем у 3.3.6, 3660 байт против 3274 в одном из моих проектов. Жаль. НУ СКОЛЬКО РАЗ ВАМ МОЖНО ПОВТОРЯТЬ. Что место в для локадьных переменных в стеке выделяеться в прологе функции. Применениие атрибута 'naked' выкидывает код пролога и эпилога из функции! Это значит что место для локальных переменных не будет выделено!!!! Анатолий.
|
|
|
|
|
Dec 25 2007, 10:18
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Различие в том, где она создается. Локальная - в прологе мэйна. Static - в секции bss, если не ошибаюсь. Знаю, я имел в виду их использование в програме (в main) одинаковое, если есть существенные различия, укажите. Цитата А массивы вроде локальными не бывают, они всегда static, даже если объявлены локальными. Но указатель стека в прологе main устанавливается в зависимости от. Правда это в 3.3.6, в 4.2.2 еще не проверил. Цитата НУ СКОЛЬКО РАЗ ВАМ МОЖНО ПОВТОРЯТЬ. Что место в для локадьных переменных в стеке выделяеться в прологе функции. Да ясно всё. Я полагаю, что без пролога в main можно прекрасно обойтись, я всегда обходился, во всяком случае. Локальные переменные в main, не static, какой-то очень частный случай, ИМХО.
Сообщение отредактировал 733259 - Dec 25 2007, 10:20
|
|
|
|
|
Dec 25 2007, 10:25
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(733259 @ Dec 25 2007, 13:18)  Да ясно всё. Я полагаю, что без пролога в main можно прекрасно обойтись, я всегда обходился, во всяком случае. Локальные переменные в main, не static, какой-то очень частный случай, ИМХО. Компилятор может создать код, которому требуеться место в стеке, даже тогда, когда вы не создавали локальных переменных. Я постараюсь вечером найти пример. Анатолий.
Сообщение отредактировал aesok - Dec 25 2007, 10:26
|
|
|
|
|
Dec 26 2007, 19:35
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(733259 @ Dec 25 2007, 07:29)  Выкидывает, но только не в main - там пролог и эпилог не нужны. Цитата(733259 @ Dec 25 2007, 09:13)  Это я знаю, какие траблы с локальными переменными main? Я не заметил никаких, вот и спрашиваю. Перечитайте основы, начать лучше всего с K&R. Ну а если повторное самообразование не поможет, то ждем от Вас скомпилированных примеров по таким исходникам: Код Ваш вариант: int main() __attribute__((naked)); int main() { unsigned char arr[10]; unsigned char i;
for (i=0;i<10;i++) arr[i]=i; while (1); return 0; } Код Правильный вариант: int main() { unsigned char arr[10]; unsigned char i;
for (i=0;i<10;i++) arr[i]=i; while (1); return 0; } Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно...
|
|
|
|
|
Dec 26 2007, 19:52
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Dec 26 2007, 22:41)  В обоих неправильно  Значение i не определено в обоих случаях, Я надеюсь что Вы таки пошутили насчет неопределенности i  (оно там от 0 до 9 считается) ну и это всего лишь был минимальный пример приведен, без копирования в память с постоянным адресом...
|
|
|
|
|
Dec 27 2007, 01:52
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(singlskv @ Dec 26 2007, 21:52)  Я надеюсь что Вы таки пошутили насчет неопределенности i  (оно там от 0 до 9 считается) Посыпаю голову окурками. Действительно, глаз замылился. Уже привык в плюсах объявлять переменную прямо в цикле. Тогда оба примера будут работать одинаково, ибо указатель стека проинициализирован, и нет ничего, что могло бы содержимое массива испортить. Но первый же вызов функции порушит все. P.S. Я просто на это уже нарывался - тоже в погоне за кодом сделал main() naked и потом разбирался, почему же все перестало работать. Для aesok: Наткнулся на такую особенность: если в программе активно используются inline - функции, некоторые из них не встраиваются, даже если просто содержат вызов другой функции (т.е. при встраивании должны соптимизироваться совсем). Добавив -Winline получаю сообщение, что достигнут лимит --param max-inline-insns-single. В документации на gcc сказано, что по умолчанию этот параметр устанавливается в 300 (600/2) "морковок" (неких внутренних единиц измерения). Установка его через командную строку равным хотя бы 30 приводит к встраиванию всех inline функций в моем проекте. Какое же значение этот параметр имеет по умолчанию в действительности? Понимаю, что вопрос скорее не к вам, ибо аналогичное поведение демонстрирует и arm-elf-gcc, но поскольку вы более глубоко "погружены" в это, может подскажете - это я что-то неправильно понял или ошибка в документации?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 27 2007, 02:03
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно... Хотелось бы получать от Вас хотя бы немного проверенный код. avr-gcc 4.2.2 ( WinAVR 20071221) Ваш цикл массив и пролог полностью выкидывает Код int main(){ 62: ff cf rjmp .-2 ; 0x62 <main>
00000064 <_exit>: 64: ff cf rjmp .-2 ; 0x64 <_exit> А вообще-то, если бы мне захотелось объявить массив в main я сделал бы его static, пролог в этом случае не нужен. По прежнему жду аргументов в пользу локальных (не static) переменных в main (не в блоке). А вооще-то если бы мне запонадобилось заполнить Ваш массив, я бы написал Код int main() __attribute__((naked)); int main(){
static unsigned char arr[10];
{ unsigned char i; unsigned char * point = arr + sizeof(arr);
for (i = sizeof(arr) - 1; i > 0; i--) *--point = i; *--point = i; }
while (1); return 0; } В случае 4.2.2 naked (как и OS_main)не обязательно, компилер выкидывает пролог самостоятельно.
|
|
|
|
|
Dec 27 2007, 11:55
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Dec 27 2007, 04:52)  Тогда оба примера будут работать одинаково, ибо указатель стека проинициализирован, и нет ничего, что могло бы содержимое массива испортить. Но первый же вызов функции порушит все. Не, не одинаково. Правда я до сих пор пользуюсь 20060421. Код с naked: Код @00000051: main 6: { +00000051: E080 LDI R24,0x00 Load immediate +00000052: 01FE MOVW R30,R28 Copy register pair +00000053: 9631 ADIW R30,0x01 Add immediate to word +00000054: 9381 ST Z+,R24 Store indirect and postincrement +00000055: 5F8F SUBI R24,0xFF Subtract immediate +00000056: 308A CPI R24,0x0A Compare with immediate +00000057: F3E0 BRCS PC-0x03 Branch if carry set 13: while (1); +00000058: CFFF RJMP PC-0x0000 Relative jump +00000059: 5F8F SUBI R24,0xFF Subtract immediate +0000005A: 308A CPI R24,0x0A Compare with immediate +0000005B: F3E0 BRCS PC-0x03 Branch if carry set +0000005C: CFFF RJMP PC-0x0000 Relative jump Код без naked: Код @00000051: main 6: { +00000051: EFC5 LDI R28,0xF5 Load immediate +00000052: E0D4 LDI R29,0x04 Load immediate +00000053: BFDE OUT 0x3E,R29 Out to I/O location +00000054: BFCD OUT 0x3D,R28 Out to I/O location 11: for (i=0;i<10;i++) arr[i]=i; +00000055: E080 LDI R24,0x00 Load immediate +00000056: 01FE MOVW R30,R28 Copy register pair +00000057: 9631 ADIW R30,0x01 Add immediate to word +00000058: 9381 ST Z+,R24 Store indirect and postincrement +00000059: 5F8F SUBI R24,0xFF Subtract immediate +0000005A: 308A CPI R24,0x0A Compare with immediate +0000005B: F3E0 BRCS PC-0x03 Branch if carry set 13: while (1); +0000005C: CFFF RJMP PC-0x0000 Relative jump на входе main r29:r28 содержит адрес стека. Как видно из рисунка, код одинаков за исключением того, что в коде с naked забыли отвести память под массив на стеке. В результате код с naked будет пытаться заполнять несуществующую память. Цитата(733259 @ Dec 27 2007, 05:03)  Хотелось бы получать от Вас хотя бы немного проверенный код. avr-gcc 4.2.2 ( WinAVR 20071221) Ваш цикл массив и пролог полностью выкидывает Он проверен на 20060421. На 20071221 добавьте какую-нить глобальную volatile переменную volatile unsigned char a; и перед while(1) напишите a=arr[5]; Цитата По прежнему жду аргументов в пользу локальных (не static) переменных в main (не в блоке). Вам уже сказали что static это глобальный массив с ограниченной видимостью. А если Вам будет нужен временный массив для рассчетов, вы его тоже static объявите ? Наверное в Ваших микроконтроллерах очень много лишней памяти...
|
|
|
|
|
Dec 27 2007, 12:34
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(733259 @ Dec 27 2007, 04:03)  По прежнему жду аргументов в пользу локальных (не static) переменных в main (не в блоке). Ну, объявление автоматических локальных переменных в любой функции - наиболее естественное действие. Это дает свободу компилятору размещать их в удобном для него месте - на стеке или в регистрах. Хотелось бы услышать от вас аргументы в пользу объявления локальных переменных статическими именно в main(). Основное отличие статических переменных от автоматических - сохранение их значения между вызовами функций. Но main() вызывается лишь однажды, поэтому сохранение значения _между_ вызовами теряет смысл. Так в чем же смысл делать локальные переменные main() статическими? Цитата(singlskv @ Dec 27 2007, 13:55)  Не, не одинаково. Какая оптимизация используется? Выкидывание кода вполне справедливо. А вы попробуйте в конце цикла суммировать элементы массива и заносить результат в глобальную переменную. И включите какое-нибудь прерывание, например от таймера. Тут-то уж точно глюк будет воспроизведен 100%.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 27 2007, 13:17
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Сергей Борщ @ Dec 27 2007, 04:52)  Для aesok: Наткнулся на такую особенность: если в программе активно используются inline - функции, некоторые из них не встраиваются, даже если просто содержат вызов другой функции (т.е. при встраивании должны соптимизироваться совсем).... Я не разбирался с inline подробно. Анатолий.
|
|
|
|
|
Dec 27 2007, 13:21
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Он проверен на 20060421. Мы обсуждаем здесь конкретную версию 20071221 и её фишки и глюки, а не основы C. Цитата На 20071221 добавьте какую-нить глобальную volatile переменную Вообще-то что-то подобное Вам стоило добавить в свой код. Цитата Вам уже сказали что static это глобальный массив с ограниченной видимостью. Так это мне и без того известно. Цитата А если Вам будет нужен временный массив для рассчетов, вы его тоже static объявите ? Нет, но и прямо в main не стану. Цитата Но main() вызывается лишь однажды, поэтому сохранение значения _между_ вызовами теряет смысл. Вот и я про то же, и те и другие используются одинаково. Цитата Так в чем же смысл делать локальные переменные main() статическими? В 3.4.6 - избавится от не нужного пролога. Ну и вооще как правило приходится писать эфективный, а не наглядный код, не гигагерцный пень же.
|
|
|
|
|
Dec 27 2007, 16:50
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Сергей Борщ @ Dec 27 2007, 15:34)  Какая оптимизация используется? -Os Цитата Выкидывание кода вполне справедливо. А вы попробуйте в конце цикла суммировать элементы массива и заносить результат в глобальную переменную. И включите какое-нибудь прерывание, например от таймера. Тут-то уж точно глюк будет воспроизведен 100%. Дык в 20060421 оно и так с naked глючит т.к. массив в такой ситуации в нем не выкидывается. Цитата(733259 @ Dec 27 2007, 16:21)  Мы обсуждаем здесь конкретную версию 20071221 и её фишки и глюки, а не основы C. Атлична, вот Вам код написанный по Вашим правилам: Код volatile unsigned long a=1; volatile unsigned long arr[8];
int main() __attribute__((naked)); int main() {
{ unsigned int i; unsigned long a1,a2,a3,a4,a5,a6,a7,a8;
a1 = a + 1; a2 = a + 2; a3 = a + 3; a4 = a + 4; a5 = a + 5; a6 = a + 6; a7 = a + 7; a8 = a + 8;
arr[0] = a1; arr[1] = a2; arr[2] = a3; arr[3] = a4; arr[4] = a5; arr[5] = a6; arr[6] = a7; arr[7] = a8; a = 0;
for (i=0;i<10;i++) a+=arr[i]; }
while (1); return 0;
} Массив вынес в глобальные и сделал volatile, т.к. он будет использоваться в прерывании... Откомпилируйте его на 20071221 с опцией -Os и расскажите какой будет результат в переменной "a" когда дойдем до бесконечного цикла.
|
|
|
|
|
Dec 27 2007, 16:56
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Дык в 20060421 оно и так с naked глючит т.к. массив в такой ситуации в нем не выкидывается. Вы вместо 20060421 версию скажите - ('avr-gcc -v'), похоже у Вас вооще трёшка.
|
|
|
|
|
Dec 27 2007, 17:55
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Ааа, переменные не влазят. Однозначно признак плохого дизайна. В данном случае легко обходится простой перестановкой строк Код a1 = a + 1; arr[0] = a1; a2 = a + 2; arr[1] = a2; Но, да готов согласится - еще одна ситуация, где naked не допустим, кроме локальных переменных.
|
|
|
|
|
Dec 27 2007, 18:47
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Вот минимальный нерабочий пример: Код __attribute__ ((naked)) int main(void) { volatile int i;
i++; } Перременая 'i' объявлена с модификатором "volatile", для того чтобы запретить оптимизатору разместить ее в регистах. Вот код который генерируеться для этой функции: Код @0000004D: main ---- demo.c --------------------------------------------------------------------------------------- 3: { +0000004D: 8189 LDD R24,Y+1 Load indirect with displacement +0000004E: 819A LDD R25,Y+2 Load indirect with displacement +0000004F: 9601 ADIW R24,0x01 Add immediate to word +00000050: 839A STD Y+2,R25 Store indirect with displacement +00000051: 8389 STD Y+1,R24 Store indirect with displacement 7: } +00000052: CFFF RJMP PC-0x0000 Relative jump Здесь происходит обращение к памяти по адресам [Y+1..Y+2] (это переменная 'i'), но регистр Y не инициализирован! Регистр Y это frame-pointer (указатель локального фрейма) , или указатель на область памяти где расположены локальные переменные. Выкинув пролог функции, вы выкинули и инициализацию frame-pointer-а. Еще раз!!! если в вашей функции 'main', для нее задан атрибут 'naked' и в ней есть локальные переменные то она будет работать только в том случае, если оптимизатор разместит все эти перемене в регистрах, и не будет использовать для их хранения локальный фрейм. Деже если сегодня ваша функция 'main' сейчас работает, вы можете гарантировать соблюдения этих условий при развитии проекта и внесении изменений в 'main'? НЕТ!!! Вы предлагаете объявлять все переменные в 'main' как static, но это тоже не дает вам 100% гарантий. Компилятор может сам создать локальные переменные для личных нужд. Анатолий.
|
|
|
|
|
Dec 27 2007, 19:07
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Вы предлагаете объявлять все переменные в 'main' как static, но это тоже не дает вам 100% гарантий. Компилятор может сам создать локальные переменные для личных нужд. Ничего подобного я не предлагаю. Я говорю о реальной практике, а не теоретических примерах. Переменная volatile может понадобится, чтобы в нее писали обработчики прерываний и т.п. Стало быть однозначно - глобальная. Мне трудно представить _реальную_ иную ситуацию. Цитата Деже если сегодня ваша функция 'main' сейчас работает, вы можете гарантировать соблюдения этих условий при развитии проекта и внесении изменений в 'main'? НЕТ!!! И что помешает мне поставить // ? Я говорю только, что naked - хорошая практика. На выше перечисленные ситуации не разу не натыкался - если завожу переменную в main, т.е. всё равно всегда существующую, хоть и локальную (теоретически) - static. Переполнять регистры и потом гонять данные в стек и обратно тоже никакого желания, про volatile уже сказал. Так что и дальше буду использовать naked.
|
|
|
|
|
Dec 27 2007, 19:12
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(733259 @ Dec 27 2007, 22:07)  И что помешает мне поставить // Ничего не помешает, только перед тем как вы догадаетесь что это нужно сделать, вы поимеете секса со своей програмой через дебагер. Хотите учиться на своих ошибках учитесь, только ПОЖАЛУЙСТА никому не советуйте использовать "naked" c функцией main. Анатолий.
Сообщение отредактировал aesok - Dec 27 2007, 19:40
|
|
|
|
|
Dec 27 2007, 19:24
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата Ничего не помешает, только перед тем как вы догадаетесь что это нужно сделать, вы поимеете секса со своей програмой через дебагер. Хтите учиться на своих ошибках учитесь, только ПОЖАЛУЙСТА никому не советуйте использовать "naked" c функцией main. Думаю моментально догадаюсь  Гораздо чаще приходится сталкиваться с наездом стека на данные при возникновении прерывания во время вызова вложеных функций.
|
|
|
|
|
Dec 27 2007, 19:26
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(733259 @ Dec 27 2007, 22:07)  Я говорю о реальной практике, а не теоретических примерах. Так что и дальше буду использовать naked. В принципе, если у Вас есть разрешение на ношение огнестрельного оружия, Вы можете поиграть и в "русскую рулетку" и никто Вам не помешает... Тока имейте в виду что это можно делать только до 11 вечера или после 6 утра чтобы не мешать соседям...
|
|
|
|
|
Dec 27 2007, 19:38
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Dec 27 2007, 22:13)  ИМХО, все-таки Y инициализирован и именно значением == SP или я не прав и это не всегда так ? В прологе выполняеться следующий псевдокод: FP = SP FP = FP - <frame_size> SP = FP где: FP - Frame Pointer, размещаеться в регистре Y SP - Stack Pointer frame_size - размер памяти необходимой для хранения локальных переменных. адреса [FP+1...FP+1+frame_size] - локальный фрейм функции. Для всех функций, которые имеют фрейм, FP = SP, и регистр FP(Y) используется в качестве базового для доступа к локальным переменным. В AVR архитектуре SP не может быть базовым регистром. Если функция не имеет фрейма регистр Y(FP) в прологе не инициализируется, и свободно используется компилятором в теле функции. Если функция naked и не имеет пролога, то FP не может быть навен SP. Если только случайно Анатолий.
Сообщение отредактировал aesok - Dec 27 2007, 19:45
|
|
|
|
|
Dec 27 2007, 19:51
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Dec 27 2007, 22:38)  Если функция naked и не имеет пролога, то FP не может быть навен SP. Если только случайно Я имел в виду не любую функцию а только main! ИМХО, при входе в main, Y всегда равен SP, ну а дальше, уже в прологе, отводится место на стеке под локальные переменные.
|
|
|
|
|
Dec 27 2007, 19:58
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Dec 27 2007, 22:51)  Я имел в виду не любую функцию а только main! ИМХО, при входе в main, Y всегда равен SP, ну а дальше, уже в прологе, отводится место на стеке под локальные переменные. Я писал про все функции, включая main и начиная с avr-gcc 4.2 + mega256 патч. В avr-gcc 3 main работает немного по другому, но это уже история. С чего вы взяли что Y == SP перед входом в полог main? Этого никто не гарантировал. Анатолий.
|
|
|
|
|
Dec 27 2007, 20:18
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Dec 27 2007, 22:58)  Я писал про все функции, включая main и начиная с avr-gcc 4.2 + mega256 патч. В avr-gcc 3 main работает немного по другому, но это уже история. может и история... тока после неудачной попытки перехода на 200701xx, я пока сижу на 2006xxxx, для меня предсказуемость генерируемого кода важнее... Цитата С чего вы взяли что Y == SP перед входом в полог main? Этого никто не гарантировал. Анатолий. А вот отсюда и взял: Код __init:
#ifndef __AVR_ASM_ONLY__ .weak __stack
/* By default, malloc() uses the current value of the stack pointer minus __malloc_margin as the highest available address.
In some applications with external SRAM, the stack can be below the data section (in the internal SRAM - faster), and __heap_end should be set to the highest address available for malloc(). */ .weak __heap_end .set __heap_end, 0
.section .init2,"ax",@progbits clr __zero_reg__ out _SFR_IO_ADDR(SREG), __zero_reg__ ldi r28,lo8(__stack) #ifdef SPH ldi r29,hi8(__stack) out _SFR_IO_ADDR(SPH), r29 #endif out _SFR_IO_ADDR(SPL), r28 Причем что у avr-libc-1.4.4 и у avr-libc-1.4.6 этот код абсолютно одинаков и кажеться давно уже не претерпевал никаких изменений... Разночтения могут возникнуть только если я начну переопределять код в секциях .initX
|
|
|
|
|
Jan 14 2008, 09:25
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Цитата(Непомнящий Евгений @ Jan 14 2008, 12:11)  Не совсем понял - зачем ломать копья из-за main? Она ровно одна, если вы сэкономите на ней несколько байт (десятков байт) - то что это даст (кроме морального удовлетворения  )? Вы правы почти ничего кроме удовлетворения, раздражает лишний код. Цитата Кстати, еще вопрос - наверное не в тему - почему нет отдельной ветки для GCC, как это сделано для IAR? Не удобно разыскивать посты, посвященные GCC, в нескольких ветках... Присоединяюсь, непонятно, ведь gcc куда более распространен.
Сообщение отредактировал 733259 - Jan 14 2008, 09:27
|
|
|
|
|
Jan 14 2008, 09:43
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Непомнящий Евгений @ Jan 14 2008, 10:11)  Не совсем понял - зачем ломать копья из-за main? Она ровно одна, если вы сэкономите на ней несколько байт (десятков байт) - то что это даст (кроме морального удовлетворения  )? Применение атрибутов OS_main и OS_task позволяет сэкономить от 0 до примерно 40 байт кода и от 0 до 16 байт RAM. Точка. Никто не обещал что добавив в программу 20 буковок и она станет в 2 раза меньше. Цитата(Непомнящий Евгений @ Jan 14 2008, 10:11)  Или речь идет о совсем младших мегах? Не только. Для ботлоадера очень важен размер кода. Анатолий.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|