|
|
  |
WinAVR-20071221 и AVR Studio 4.13 SP2 Final, новые релизы программ |
|
|
|
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.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|