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

 
 
 
Reply to this topicStart new topic
> Ошибки компилятора, или сам дурак?
Sergio66
сообщение Feb 12 2013, 09:35
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526



Имеется
IAR C/C++ Compiler for AVR
6.11.1 (6.11.1.50453)
Имеется код (см ниже). Проблема в том, что переменная, которая передается в качестве параметра в функцию, портится этой самой функцией. Переменная хранится а R25, передается нормально... Но вызываемая функция, использую данный регистр, не сохраняет его...
Вот код:
Код
37:                      if (LoadAppSec(currentFlash-1)) {
+00003C19:   2F09        MOV       R16,R25        Copy register
+00003C1A:   D136        RCALL     PC+0x0137      Relative call subroutine
+00003C1B:   2300        TST       R16            Test for Zero or Minus
+00003C1C:   F081        BREQ      PC+0x11        Branch if equal
.............................................................................


Вот эта функция - LoadAppSec -> RCALL PC+0x0137

CODE
415: bool LoadAppSec(UCHAR flash)
416: {
+00003D51: 938A ST -Y,R24 Store indirect and predecrement
+00003D52: 2F80 MOV R24,R16 Copy register
419: cnt = 0;
+00003D53: E000 LDI R16,0x00 Load immediate
+00003D54: E7E7 LDI R30,0x77 Load immediate
+00003D55: E0F2 LDI R31,0x02 Load immediate
+00003D56: D00B RCALL PC+0x000C Relative call subroutine
420: Beep();
+00003D57: DE79 RCALL PC-0x0186 Relative call subroutine
421: print_s_(Start_Load);
+00003D58: E60E LDI R16,0x6E Load immediate
+00003D59: E710 LDI R17,0x70 Load immediate
+00003D5A: DF9B RCALL PC-0x0064 Relative call subroutine
422: FLASH_READY_LED_ON;
+00003D5B: 9AC3 SBI 0x18,3 Set bit in I/O register
423: res = loader(flash);
+00003D5C: 2F08 MOV R16,R24 Copy register
+00003D5D: 940E3DA9 CALL 0x00003DA9 Call subroutine
424: FLASH_READY_LED_OFF;
+00003D5F: 98C3 CBI 0x18,3 Clear bit in I/O register
425: return res;
+00003D60: 9189 LD R24,Y+ Load indirect and postincrement
+00003D61: 9508 RET Subroutine return
@00003D62: ?Subroutine5


В данном случае, регистр R25 не трогается, потому и не сохраняется.
Далее вызывается функция CALL 0x00003DA9 (res = loader(flash))

CODE
+00003DA9: 9760 SBIW R28,0x10 Subtract immediate from word
+00003DAA: 2EE0 MOV R14,R16 Copy register
123: cnt = 0;
+00003DAB: E000 LDI R16,0x00 Load immediate
+00003DAC: E7E7 LDI R30,0x77 Load immediate
+00003DAD: E0F2 LDI R31,0x02 Load immediate
+00003DAE: 8300 STD Z+0,R16 Store indirect with displacement
+00003DAF: 8301 STD Z+1,R16 Store indirect with displacement
+00003DB0: 8302 STD Z+2,R16 Store indirect with displacement
+00003DB1: 8303 STD Z+3,R16 Store indirect with displacement
130: unsigned char *p = chainCipherBlock;
+00003DB2: 019E MOVW R18,R28 Copy register pair
131: unsigned char BOOTFLASH *q = initialVector;
+00003DB3: E000 LDI R16,0x00 Load immediate
+00003DB4: E711 LDI R17,0x71 Load immediate
132: unsigned char n = 16;
+00003DB5: E140 LDI R20,0x10 Load immediate
136: *p++ = *q++;
+00003DB6: 01F8 MOVW R30,R16 Copy register pair
+00003DB7: 9155 LPM R21,Z+ Load program memory and postincrement
+00003DB8: 018F MOVW R16,R30 Copy register pair
+00003DB9: 01F9 MOVW R30,R18 Copy register pair
+00003DBA: 9351 ST Z+,R21 Store indirect and postincrement
+00003DBB: 019F MOVW R18,R30 Copy register pair
138: while (--n);
+00003DBC: 954A DEC R20 Decrement
+00003DBD: F7C1 BRNE PC-0x07 Branch if not equal
141: aesInit( tempbuf ); // Init AES algorithm.
+00003DBE: E900 LDI R16,0x90 Load immediate
+00003DBF: 2E40 MOV R4,R16 Copy register
+00003DC0: E002 LDI R16,0x02 Load immediate
+00003DC1: 2E50 MOV R5,R16 Copy register
+00003DC2: 0182 MOVW R16,R4 Copy register pair
+00003DC3: 940E3B7D CALL 0x00003B7D Call subroutine
148: WDTCR |= (1<<WDTOE) | (1<<WDE) | (1<<WDP0) | (1<<WDP2);
+00003DC5: B501 IN R16,0x21 In from I/O location
+00003DC6: 610D ORI R16,0x1D Logical OR with immediate
+00003DC7: BD01 OUT 0x21,R16 Out to I/O location
160: if (repeat) cnt = previous_frame_address;
+00003DC8: 9100028F LDS R16,0x028F Load direct from data space
+00003DCA: 2300 TST R16 Test for Zero or Minus
+00003DCB: F051 BREQ PC+0x0B Branch if equal
160: if (repeat) cnt = previous_frame_address;
+00003DCC: E8EB LDI R30,0x8B Load immediate
+00003DCD: E0F2 LDI R31,0x02 Load immediate
+00003DCE: D0BB RCALL PC+0x00BC Relative call subroutine
+00003DCF: E7E7 LDI R30,0x77 Load immediate
+00003DD0: E0F2 LDI R31,0x02 Load immediate
+00003DD1: D0BD RCALL PC+0x00BE Relative call subroutine
+00003DD2: C003 RJMP PC+0x0004 Relative jump
335: repeat = 0;
+00003DD3: E000 LDI R16,0x00 Load immediate
+00003DD4: 9300028F STS 0x028F,R16 Store direct to data space
162: previous_frame_address = cnt;
+00003DD6: E7E7 LDI R30,0x77 Load immediate
+00003DD7: E0F2 LDI R31,0x02 Load immediate
+00003DD8: D0B1 RCALL PC+0x00B2 Relative call subroutine
+00003DD9: E8EB LDI R30,0x8B Load immediate
+00003DDA: E0F2 LDI R31,0x02 Load immediate
+00003DDB: D0B3 RCALL PC+0x00B4 Relative call subroutine
163: __watchdog_reset();
+00003DDC: 95A8 WDR Watchdog reset
164: frameSize = ((frameindex_t)ConvHDToByte(busReceiveByte(repeat, flash),busReceiveByte(0,flash)) << 8) |
165: ConvHDToByte(busReceiveByte(0,flash),busReceiveByte(0,flash));
+00003DDD: D0BA RCALL PC+0x00BB Relative call subroutine
+00003DDE: 9100028F LDS R16,0x028F Load direct from data space
+00003DE0: 940E3EBE CALL 0x00003EBE Call subroutine
+00003DE2: D0A5 RCALL PC+0x00A6 Relative call subroutine
+00003DE3: D0B4 RCALL PC+0x00B5 Relative call subroutine
+00003DE4: D0B0 RCALL PC+0x00B1 Relative call subroutine
+00003DE5: D0A2 RCALL PC+0x00A3 Relative call subroutine
+00003DE6: 2FA0 MOV R26,R16 Copy register
170: unsigned char *p = rxBuffer;
+00003DE7: 0132 MOVW R6,R4 Copy register pair
171: n = frameSize;
+00003DE8: 2FB0 MOV R27,R16 Copy register
173: crc = 0;
+00003DE9: E080 LDI R24,0x00 Load immediate
+00003DEA: E090 LDI R25,0x00 Load immediate


Вот собственно, мне кажется что далее этого места и не нужно.
Видно. что данная ф-я нигде не сохраняет R25? но с успехом его использует...
Что это?
На "Сам дурак" не обижусь... ...если объясните почему...
Спасибо...

Сообщение отредактировал IgorKossak - Feb 12 2013, 21:31
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
KRS
сообщение Feb 12 2013, 10:36
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



листинг функции
Цитата
CALL 0x00003DA9 (res = loader(flash))

не полный!
Go to the top of the page
 
+Quote Post
Sergio66
сообщение Feb 12 2013, 10:46
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526



Цитата(KRS @ Feb 12 2013, 14:36) *
листинг функции

не полный!


Я остановил листинг на том месте, после которого уже все равно, что происходит. R25 используется функцией без предварительного сохранения. Т.о. не имеет значения, что там дальше в этой функции. Не стал перегружать страницу...
Go to the top of the page
 
+Quote Post
SSerge
сообщение Feb 12 2013, 11:06
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Разгадка проста.
Параметр в Вашу функцию передаётся в регистре R16 и в нём-же возвращается результат.
Команда MOV R16,R25 перед вызовом копирует из R25 в R16.
В функции первым делом R24 сохраняется в стек(ST -Y,R24), затем R16 копируется в R24 и дальше используется чтобы ещё раз скопировать его в R16 и вызвать функцию loader(). Перед выходом прежнее содержимое R24 восстанавливается из стека(LD R24,Y+).


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
Sergio66
сообщение Feb 12 2013, 12:54
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526



Цитата(SSerge @ Feb 12 2013, 15:06) *
Разгадка проста.
Параметр в Вашу функцию передаётся в регистре R16 и в нём-же возвращается результат.
Команда MOV R16,R25 перед вызовом копирует из R25 в R16.
В функции первым делом R24 сохраняется в стек(ST -Y,R24), затем R16 копируется в R24 и дальше используется чтобы ещё раз скопировать его в R16 и вызвать функцию loader(). Перед выходом прежнее содержимое R24 восстанавливается из стека(LD R24,Y+).


1. Команда MOV R16,R25 перед вызовом копирует из R25 в R16. Это не сохранение контекста, а передача параметра. R25 остается со своим содержимым, которое, кстати говоря, есть управляющая переменная цикла while.
2. Насколько мне известно, любая функция, если она затрагивает какие то регистры, должна их сначала сохранять в стеке, а затем, восстанавливать...
3. Вы предложили не разгадку, а описание того, что я итак вижу...
Я хочу понимать, что я не так сделал, что функция меняет значение переменной, определенной на внешнем по отношению к ней уровне.. На мой взгляд, это нонсенс. Скажу больше. Эта программа работала нормально, пока был цикл
flash = 2; (размещена в R25)
while (flash) {
...
flash--;
}

как только я поменял цикл на
do {
...
flash--;
} while (flash)
началась вот такая абракадабра...
Насколько я понимаю, что то работает не так... или компилятор с оптимизатором, или моя голова...
Go to the top of the page
 
+Quote Post
SSerge
сообщение Feb 12 2013, 14:30
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Пардон, был невнимателен.
Согласно Calling convention из EWAVR_CompilerReference.pdf должно быть так:
регистры, которые Scratch registers (R0-R3, R16-R23, and R30-R31), функции дозволяется портить,
а вот остальные - Preserved registers (R4-R15 and R24-R27), если используются, необходимо сохранять и восстанавливать перед выходом.

Так что в фунции loader компилятор должен был сохранить оба регистра - R24 и R25.
Да, похоже на баг оптимизатора.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Feb 12 2013, 16:18
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(Sergio66 @ Feb 12 2013, 18:54) *
Эта программа работала нормально, пока был цикл
flash = 2; (размещена в R25)
while (flash) {
...
flash--;
}

как только я поменял цикл на
do {
...
flash--;
} while (flash)
началась вот такая абракадабра...

А листинг цикла можно показать? Кстати, первый вариант цикла, на мой взгляд, более "безопасный". Во втором варианте, если при входе в цикл переменная flash == 0, то цикл будет повторятся (2 ^ разрядность flash) раз.

Или, если flash == 2 всегда, не мог компилятор развернуть цикл???


--------------------
Go to the top of the page
 
+Quote Post
Sergio66
сообщение Feb 12 2013, 17:49
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526



Цитата(prottoss @ Feb 12 2013, 20:18) *
А листинг цикла можно показать? Кстати, первый вариант цикла, на мой взгляд, более "безопасный". Во втором варианте, если при входе в цикл переменная flash == 0, то цикл будет повторятся (2 ^ разрядность flash) раз.

Или, если flash == 2 всегда, не мог компилятор развернуть цикл???

Цикл всегда начинается с flash=2 и выполняется для двух флэш.
Сначала для N 2, потом для N 1 . Листинг цикла смогу выложить завтра. Но поверь, Андрей, данная переменная компиллятором размещена именно в R25.
Если помнишь, я уже несколько раз такое обнаруживал. Мы уже дискутировали с тобой на эту тему. Вот отловить и выложить удалось первый раз. Остальные разы я обходил такие штуки размещением переменной не в регистрах а в памяти. Но это кривое решение. Хотелось бы понять причину. Иначе такие штуки будут повторяться вновь, как у меня это несколько раз происходило...
Go to the top of the page
 
+Quote Post
KRS
сообщение Feb 12 2013, 21:12
Сообщение #9


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Sergio66 @ Feb 12 2013, 21:49) *
Остальные разы я обходил такие штуки размещением переменной не в регистрах а в памяти. Но это кривое решение. Хотелось бы понять причину. Иначе такие штуки будут повторяться вновь, как у меня это несколько раз происходило...

Что бы понять нужен полный листинг из lst файла и что бы были видны полные прототипы функций
может быть компилятор их заинлайнил или выделил исключительно во внутренние подпрограммы.
А с оптимизацией циклов у IAR бывают проблемы, взять хотя бы соседнюю тему про АРМ.
Но вот что бы регистры в функции не сохранять...
Go to the top of the page
 
+Quote Post
Палыч
сообщение Feb 13 2013, 07:41
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Sergio66 @ Feb 12 2013, 16:54) *
flash = 2; (размещена в R25)

Можно полюбопытствовать: каким образом переменная flash оказалась размещена в R25 ? Это компилятор сам её там разместил ? Или это Вы велели компилятору (например, с помощью __regvar ..... @ 25) разместить её там ? Если - последнее, то - "сам дурак"... Хотя и с компиляторописателей вину снимать не нужно. rolleyes.gif
Go to the top of the page
 
+Quote Post
Sergio66
сообщение Feb 13 2013, 09:14
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526



Цитата(Палыч @ Feb 13 2013, 11:41) *
Можно полюбопытствовать: каким образом переменная flash оказалась размещена в R25 ? Это компилятор сам её там разместил ? Или это Вы велели компилятору (например, с помощью __regvar ..... @ 25) разместить её там ? Если - последнее, то - "сам дурак"... Хотя и с компиляторописателей вину снимать не нужно. rolleyes.gif

Вы не поверите, но эту переменную там разместил именно компилятор.
Кстати, с подобными ошибками я сталкиваюсь не впервые.
Я уже писал на форуме, что функция портит переменную, которая для нее является внешней, объявлена на внешнем уровне...
Очень хотелось бы понять, в чем именно дело, т.к. при таком раскладе, не знаешь, где и что еще выплывет. Такие вещи как то не принято глубоко тестировать... Как то не хочется в отладчике проверять, как работает, например, каждый цикл программы, или как ведут себя переменные после вызовов функций...
Go to the top of the page
 
+Quote Post
KRS
сообщение Feb 13 2013, 10:58
Сообщение #12


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(Sergio66 @ Feb 13 2013, 13:14) *
Я уже писал на форуме, что функция портит переменную, которая для нее является внешней, объявлена на внешнем уровне...

У вас функция портит регистр!
В любом случае что бы понять нужен полный листинг и исходник.


Цитата(Палыч @ Feb 13 2013, 11:41) *
Или это Вы велели компилятору (например, с помощью __regvar ..... @ 25) разместить её там ?

Компилер "пошлет" сразу, можно только 4 - 15 регистры использовать, к тому же они еще должны быть зарезервированы опцией.

Цитата(Sergio66 @ Feb 12 2013, 13:35) *
Код
+00003C1A:   D136        RCALL     PC+0x0137      Relative call subroutine

А что это за листинг? коменты к инструкциям реально раздражают, потому что не несут никакого смысла.
IAR генерит вполне приличный листинг (если его попросить) и исходник на asm тоже.
Go to the top of the page
 
+Quote Post
bbill
сообщение Feb 18 2013, 22:09
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 76
Регистрация: 21-10-05
Пользователь №: 9 941



Чтобы не создавать новую тему.

Кто-нибудь сравнивал новый IAR 6.20.1 for AVR с версиями 5.51 и 6.11. Интересует разница в размере выходного кода при одинаковых условиях оптимизации.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Feb 24 2013, 21:22
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(bbill @ Feb 19 2013, 01:09) *
Кто-нибудь сравнивал новый IAR 6.20.1 for AVR с версиями 5.51 и 6.11. Интересует разница в размере выходного кода при одинаковых условиях оптимизации.

5.11 у меня круче компилит ... )))
Go to the top of the page
 
+Quote Post

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

 


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


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