реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> WinAVR-20071221 и AVR Studio 4.13 SP2 Final, новые релизы программ
singlskv
сообщение Dec 26 2007, 19:35
Сообщение #31


дятел
*****

Группа: Свой
Сообщений: 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;
}

Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 26 2007, 19:41
Сообщение #32


Гуру
******

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



Цитата(singlskv @ Dec 26 2007, 21:35) *
Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно...
В обоих неправильно biggrin.gif biggrin.gif Значение i не определено в обоих случаях, содержимое массивов будет одинаково-случайным. Ошибка проявится, если после заполнения массива вызвать какую-либо функцию. В этом случае при (naked) содержимое массива (и i) будет испорчено стеком вызванной функции.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 26 2007, 19:52
Сообщение #33


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Сергей Борщ @ Dec 26 2007, 22:41) *
В обоих неправильно biggrin.gif biggrin.gif Значение i не определено в обоих случаях,

Я надеюсь что Вы таки пошутили насчет неопределенности i smile.gif
(оно там от 0 до 9 считается)
ну и это всего лишь был минимальный пример приведен, без копирования в память с постоянным
адресом...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 27 2007, 01:52
Сообщение #34


Гуру
******

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



Цитата(singlskv @ Dec 26 2007, 21:52) *
Я надеюсь что Вы таки пошутили насчет неопределенности i smile.gif
(оно там от 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)
Go to the top of the page
 
+Quote Post
733259
сообщение Dec 27 2007, 02:03
Сообщение #35


Местный
***

Группа: Участник
Сообщений: 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)не обязательно, компилер выкидывает пролог самостоятельно.
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 27 2007, 11:55
Сообщение #36


дятел
*****

Группа: Свой
Сообщений: 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 объявите ?
Наверное в Ваших микроконтроллерах очень много лишней памяти...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 27 2007, 12:34
Сообщение #37


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
aesok
сообщение Dec 27 2007, 13:17
Сообщение #38


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(Сергей Борщ @ Dec 27 2007, 04:52) *
Для aesok: Наткнулся на такую особенность: если в программе активно используются inline - функции, некоторые из них не встраиваются, даже если просто содержат вызов другой функции (т.е. при встраивании должны соптимизироваться совсем)....


Я не разбирался с inline подробно.

Анатолий.
Go to the top of the page
 
+Quote Post
733259
сообщение Dec 27 2007, 13:21
Сообщение #39


Местный
***

Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146



Цитата
Он проверен на 20060421.
Мы обсуждаем здесь конкретную версию 20071221 и её фишки и глюки, а не основы C.
Цитата
На 20071221 добавьте какую-нить глобальную volatile переменную
Вообще-то что-то подобное Вам стоило добавить в свой код.
Цитата
Вам уже сказали что static это глобальный массив с ограниченной видимостью.
Так это мне и без того известно.
Цитата
А если Вам будет нужен временный массив для рассчетов, вы его тоже static объявите ?
Нет, но и прямо в main не стану.

Цитата
Но main() вызывается лишь однажды, поэтому сохранение значения _между_ вызовами теряет смысл.
Вот и я про то же, и те и другие используются одинаково.
Цитата
Так в чем же смысл делать локальные переменные main() статическими?
В 3.4.6 - избавится от не нужного пролога. Ну и вооще как правило приходится писать эфективный, а не наглядный код, не гигагерцный пень же.
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 27 2007, 16:50
Сообщение #40


дятел
*****

Группа: Свой
Сообщений: 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" когда дойдем до бесконечного цикла.
Go to the top of the page
 
+Quote Post
733259
сообщение Dec 27 2007, 16:56
Сообщение #41


Местный
***

Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146



Цитата
Дык в 20060421 оно и так с naked глючит т.к. массив в такой ситуации в нем не выкидывается.
Вы вместо 20060421 версию скажите - ('avr-gcc -v'), похоже у Вас вооще трёшка.
Go to the top of the page
 
+Quote Post
singlskv
сообщение Dec 27 2007, 17:02
Сообщение #42


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(733259 @ Dec 27 2007, 19:56) *
Вы вместо 20060421 версию скажите - ('avr-gcc -v'), похоже у Вас вооще трёшка.
это 3.4.6
Жду результата проверки последнего примера на 2007...
Go to the top of the page
 
+Quote Post
733259
сообщение Dec 27 2007, 17:55
Сообщение #43


Местный
***

Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146



Ааа, переменные не влазят. Однозначно признак плохого дизайна. В данном случае легко обходится простой перестановкой строк
Код
    a1 = a + 1;
    arr[0] = a1;
    a2 = a + 2;
    arr[1] = a2;
Но, да готов согласится - еще одна ситуация, где naked не допустим, кроме локальных переменных.
Go to the top of the page
 
+Quote Post
aesok
сообщение Dec 27 2007, 18:47
Сообщение #44


Знающий
****

Группа: Участник
Сообщений: 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% гарантий. Компилятор может сам создать локальные переменные для личных нужд.


Анатолий.
Go to the top of the page
 
+Quote Post
733259
сообщение Dec 27 2007, 19:07
Сообщение #45


Местный
***

Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146



Цитата
Вы предлагаете объявлять все переменные в 'main' как static, но это тоже не дает вам 100% гарантий. Компилятор может сам создать локальные переменные для личных нужд.
Ничего подобного я не предлагаю.
Я говорю о реальной практике, а не теоретических примерах. Переменная volatile может понадобится, чтобы в нее писали обработчики прерываний и т.п. Стало быть однозначно - глобальная. Мне трудно представить _реальную_ иную ситуацию.
Цитата
Деже если сегодня ваша функция 'main' сейчас работает, вы можете гарантировать соблюдения этих условий при развитии проекта и внесении изменений в 'main'? НЕТ!!!
И что помешает мне поставить // ? Я говорю только, что naked - хорошая практика. На выше перечисленные ситуации не разу не натыкался - если завожу переменную в main, т.е. всё равно всегда существующую, хоть и локальную (теоретически) - static. Переполнять регистры и потом гонять данные в стек и обратно тоже никакого желания, про volatile уже сказал. Так что и дальше буду использовать naked.
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01502 секунд с 7
ELECTRONIX ©2004-2016