|
|
  |
Ошибки компилятора, или сам дурак? |
|
|
|
Feb 12 2013, 09:35
|
Местный
  
Группа: Свой
Сообщений: 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] - для короткого!!!
|
|
|
|
|
Feb 12 2013, 10:46
|
Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526

|
Цитата(KRS @ Feb 12 2013, 14:36)  листинг функции
не полный! Я остановил листинг на том месте, после которого уже все равно, что происходит. R25 используется функцией без предварительного сохранения. Т.о. не имеет значения, что там дальше в этой функции. Не стал перегружать страницу...
|
|
|
|
|
Feb 12 2013, 12:54
|
Местный
  
Группа: Свой
Сообщений: 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) началась вот такая абракадабра... Насколько я понимаю, что то работает не так... или компилятор с оптимизатором, или моя голова...
|
|
|
|
|
Feb 12 2013, 14:30
|
Профессионал
    
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Feb 12 2013, 16:18
|

Гуру
     
Группа: Свой
Сообщений: 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 всегда, не мог компилятор развернуть цикл???
--------------------
|
|
|
|
|
Feb 12 2013, 17:49
|
Местный
  
Группа: Свой
Сообщений: 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. Если помнишь, я уже несколько раз такое обнаруживал. Мы уже дискутировали с тобой на эту тему. Вот отловить и выложить удалось первый раз. Остальные разы я обходил такие штуки размещением переменной не в регистрах а в памяти. Но это кривое решение. Хотелось бы понять причину. Иначе такие штуки будут повторяться вновь, как у меня это несколько раз происходило...
|
|
|
|
|
Feb 12 2013, 21:12
|

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

|
Цитата(Sergio66 @ Feb 12 2013, 21:49)  Остальные разы я обходил такие штуки размещением переменной не в регистрах а в памяти. Но это кривое решение. Хотелось бы понять причину. Иначе такие штуки будут повторяться вновь, как у меня это несколько раз происходило... Что бы понять нужен полный листинг из lst файла и что бы были видны полные прототипы функций может быть компилятор их заинлайнил или выделил исключительно во внутренние подпрограммы. А с оптимизацией циклов у IAR бывают проблемы, взять хотя бы соседнюю тему про АРМ. Но вот что бы регистры в функции не сохранять...
|
|
|
|
|
Feb 13 2013, 09:14
|
Местный
  
Группа: Свой
Сообщений: 235
Регистрация: 9-02-05
Пользователь №: 2 526

|
Цитата(Палыч @ Feb 13 2013, 11:41)  Можно полюбопытствовать: каким образом переменная flash оказалась размещена в R25 ? Это компилятор сам её там разместил ? Или это Вы велели компилятору (например, с помощью __regvar ..... @ 25) разместить её там ? Если - последнее, то - "сам дурак"... Хотя и с компиляторописателей вину снимать не нужно.  Вы не поверите, но эту переменную там разместил именно компилятор. Кстати, с подобными ошибками я сталкиваюсь не впервые. Я уже писал на форуме, что функция портит переменную, которая для нее является внешней, объявлена на внешнем уровне... Очень хотелось бы понять, в чем именно дело, т.к. при таком раскладе, не знаешь, где и что еще выплывет. Такие вещи как то не принято глубоко тестировать... Как то не хочется в отладчике проверять, как работает, например, каждый цикл программы, или как ведут себя переменные после вызовов функций...
|
|
|
|
|
Feb 13 2013, 10:58
|

Профессионал
    
Группа: Модераторы
Сообщений: 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 тоже.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|