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

 
 
 
Reply to this topicStart new topic
> как узнать в программе последний адрес этой программы (WinAVR)
injen-d
сообщение Apr 8 2008, 18:46
Сообщение #1


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

Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250



Пользую WinAVR-20071221. Возникла необходимость подсчитывать контрольную сумму программы, но не получается из самой программы узнать до куда, собственно, считать.
Думаю, нужно посчитать до адреса _еtext + длинна(.data), но реализовать это чет пока никак не получается. Должно же быть простое решение? Поиск пока ничего вразумительного не дал.
Наставьте, пожалуста, на путь истиный.
ЗЫ: на асме это делалось элементарно... crying.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 8 2008, 21:36
Сообщение #2


Гуру
******

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



Цитата(injen-d @ Apr 8 2008, 21:46) *
Пользую WinAVR-20071221. Возникла необходимость подсчитывать контрольную сумму программы, но не получается из самой программы узнать до куда, собственно, считать.
Как советует zltigo, храните в заранее оговоренном месте в начале программы (например, сразу после векторов) адрес, по которому расположена контрольная сумма.

Цитата(injen-d @ Apr 8 2008, 21:46) *
Думаю, нужно посчитать до адреса _еtext + длинна(.data), но реализовать это чет пока никак не получается. Должно же быть простое решение?

объявляете в скрипте линкера, в самом конце раздела SECTIONS фиктивный кусочек выходной секции .text (чтобы он разместился после уже заполненной .text и инициализирующих значений .data), объявляете в нем символ и присваиваете ему значение текущего адреса:
Код
SECTIONS
{
    ........
  .text :
  {
      _app_end = .;
  } > text
}
а в программе объявляете фиктивную внешнюю переменную с таким именем и берете ее адрес.

Цитата(injen-d @ Apr 8 2008, 21:46) *
ЗЫ: на асме это делалось элементарно... crying.gif
Можно пример?


--------------------
На любой вопрос даю любой ответ
"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
_Pasha
сообщение Apr 8 2008, 23:15
Сообщение #3


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



А чем плохо CRC всего набортного флеша (либо до boot - секции) ?
На асме ставится метка в главном файле в самом конце
Код
................
ZZLast_Code:
                      nop


а хранить CRC имхо лучше в последних двух байтах (опять же, либо перед boot либо там где FLASHEND)

название метки содержит достаточное кол-во ZZZ, чтобы имя было в конце таблицы символов smile.gif
Go to the top of the page
 
+Quote Post
amw
сообщение Apr 9 2008, 09:29
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847



Цитата(Сергей Борщ @ Apr 9 2008, 00:36) *
Как советует zltigo, храните в заранее оговоренном месте в начале программы (например, сразу после векторов) адрес, по которому расположена контрольная сумма.
объявляете в скрипте линкера, в самом конце раздела SECTIONS фиктивный кусочек выходной секции .text (чтобы он разместился после уже заполненной .text и инициализирующих значений .data), объявляете в нем символ и присваиваете ему значение текущего адреса:
Код
SECTIONS
{
    ........
  .text :
  {
      _app_end = .;
  } > text
}
а в программе объявляете фиктивную внешнюю переменную с таким именем и берете ее адрес.

Можно пример?

+1


--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть.
© Lewis Carroll. Alice's adventures in wonderland.
Go to the top of the page
 
+Quote Post
injen-d
сообщение Apr 9 2008, 16:43
Сообщение #5


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

Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250



Цитата
Как советует zltigo, храните в заранее оговоренном месте в начале программы (например, сразу после векторов) адрес, по которому расположена контрольная сумма.

Не, контрольную сумму (КС) храню в EEPROM, а адрес КС в EEPROM -- простая константа.
Цитата
объявляете в скрипте линкера, в самом конце раздела SECTIONS фиктивный кусочек выходной секции .text (чтобы он разместился после уже заполненной .text и инициализирующих значений .data), объявляете в нем символ и присваиваете ему значение текущего адреса

Попробовал, не подходит. В этом случае _app_end у меня всегда равно уже существующей _etext.
Цитата
а в программе объявляете фиктивную внешнюю переменную с таким именем и берете ее адрес.

А как правильно объявить? Какого она должна быть типа? У меня в итоге получилось, но как-то "через одно место" это работает, но работает правильно.
Цитата
(injen-d @ Apr 8 2008, 21:46) ЗЫ: на асме это делалось элементарно... Можно пример?

_Pasha Вам ответил, это банальная метка в конце программы.

Цитата
А чем плохо CRC всего набортного флеша (либо до boot - секции) ?

Пока хватает простого побайтового суммирования по модулю 256 или 65536, по вкусу.
И зачем контролировать неиспользуемые байты? При порче хоть одного из них, программа начнет бить ложную тревогу, оставаясь при этом полностью работоспособной. А вдруг это (порча) случится
"на самом интересном" biggrin.gif

Как я уже сказал, _app_end у меня всегда равно уже существующей _etext, а _edata = (0x100 + количество инициализируемых переменных (при выравнивании, еще +1))
девайс - ATmega645;
По hex-файлу убедился, что _etext меньше адреса последнего записываемого во флеш байта как раз на количество инициализируемых переменных(ес-но "байтовость" переменных тоже учел),
таким образом объявляем в скрипте линкера в самом конце:
Код
          ......
  _size_prog = _etext +(_edata -0x100);
}

далее используем в функции подсчета.

Привожу свою функцию, может кому будет интересно. В железе пока не проверял, за его отсутствием, но данный алгоритм (реализованный на асме) успешно работает в других готовых девайсах.

Как надо объявлять в функции переменную _size_prog, на сколько я убедился - без разницы, но есть важная особенность: переменная _size_prog не содержит ничего, а вот ее адрес и есть адрес последнего байта, записываемого во флеш.
При попытке использовать _size_prog как есть, компилятор генерит код, пытающийся загрузить значение из ОЗУ с адреса последнего используемого байта во флеш!

Код
//===================================================================
//Функция считает побайтовою сумму flash-памяти с 0 по последний используемый байт;
//Контрольная сумма (КС) хранится в EEPROM;
//Если в EEPROM имеется достоверная КС (байт в EEPROM по адресу f_ee_summ равен 0xAE), то сравнение,
//если нет (первое включение МК после программирования), то запись в EEPROM подсчитанной суммы и
//значения 0xAE по адресу f_ee_summ, затем рекурсивный вызов самой себя;
//Возвращаемое значение: 0 - норма, 0x12 - код ошибки "Ошибка контрольной суммы памяти программ";
#define ee_summ     0x40  //адрес расположения в EEPROM контрольной суммы
#define f_ee_summ     0x30  //адрес в EEPROM флага наличия посчитанной контрольной суммы
extern const uint8_t  _size_prog; //переменная _size_prog должна быть определена в скрипте линкера,
                      //в конце SECTIONS, следующим образом: _size_prog =_etext +(_edata-0x100);  uint8_t summ_flash(void)
{
    uint16_t  summ = 0;
    uint16_t  adr  = 0;
    uint8_t    f_err;
    do
    {
      summ += (uint16_t)pgm_read_byte(adr);   //побайтовое суммирование; сумма 16-битовая
      adr++;
    } while (adr < (const uint16_t)(&_size_prog)+1); //пока адрес меньше, чем (последний байт во Flash)+1
    if (eeprom_read_byte((uint8_t*)f_ee_summ)==0xAE)  //если имеется посчитанная сумма
    {
      if (eeprom_read_word((uint16_t*)ee_summ) != summ)     //если контрольная сумма не совпала-
            f_err = 0x12;                          // - вернуть код ошибки,
            else     f_err = 0;                    // иначе - 0;
    }
    else            //если посчитанной суммы нет (первое включение МК после программирования)
    {
      eeprom_write_word((uint16_t*)ee_summ, summ); //запись подсчитанной суммы
      eeprom_write_byte((uint8_t*)f_ee_summ, 0xAE);  //запись флага наличия достоверной суммы
      while(EECR & (1<<EEWE));                     //ждать окончания записи в EEPROM
      f_err = summ_flash();
    }
    return f_err;
}
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 9 2008, 18:20
Сообщение #6


Гуру
******

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



Цитата(injen-d @ Apr 9 2008, 19:43) *
Не, контрольную сумму (КС) храню в EEPROM, а адрес КС в EEPROM -- простая константа.
А смысл? Почему не хранить ее прямо во флеше, в конце прошивки? Тогда вероятность ее порчи будет такая же, как и для остальных байтов прошивки.
Цитата(injen-d @ Apr 9 2008, 19:43) *
Попробовал, не подходит. В этом случае _app_end у меня всегда равно уже существующей _etext.
Возможно, вы вставили ее не в самый конец, а до объявления секции .data? Я перед написанием того ответа специально поробовал, проходит (правда пробовал на arm-elf-gcc). И у меня скрипт несколько отличается от скриптов из комплекта avr-libc. Вместо ручного подсчета размеров и принудительного задания адресов
Код
  .data      : AT (ADDR (.text) + SIZEOF (.text))
  {
      ......
  }  > data
  .bss  SIZEOF(.data) + ADDR(.data) :
  {
      .......
  }  > data
я даю возможность линкеру самому все это считать:
Код
.data :
  {
      .......
  }  > data AT > text
  .bss :
  {
      .......
  }  > data

Цитата(injen-d @ Apr 9 2008, 19:43) *
А как правильно объявить? Какого она должна быть типа? У меня в итоге получилось, но как-то "через одно место" это работает, но работает правильно.
да любого типа. Вас же интересует ее адрес. Если вы сумируете память побайтно, то и ее разумно объявить байтом, чтобы получился указатель на байт.
Цитата(injen-d @ Apr 9 2008, 19:43) *
_Pasha Вам ответил, это банальная метка в конце программы.
У меня тоже получилась банальная метка _app_end в конце программы. А если программа состоит из нескольких отдельно компилируемых файлов, то без скрипта линкера не обойтись, будь она на ассемблере или С.


--------------------
На любой вопрос даю любой ответ
"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
injen-d
сообщение Apr 9 2008, 19:26
Сообщение #7


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

Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250



Цитата
А смысл? Почему не хранить ее прямо во флеше, в конце прошивки? Тогда вероятность ее порчи будет такая же, как и для остальных байтов прошивки.

Что-то в этом есть... Будет свободное время - сделаю вариант с хранением суммы во flash, не будет - оставлю как есть.
Цитата
Возможно, вы вставили ее не в самый конец, а до объявления секции .data?

Нет. Сделал в точности как Вы указывали: в самом конце SECTIONS { }.
Только что перепроверил: _app_end == _etext -- значения для инициализации переменных расположены в последующих байтах.
Использую скопированный из winavr соответствующий файл скрипта (avr5.x).
Попробовал переделать как у Вас
Код
я даю возможность линкеру самому все это считать:   .data :    {        .......    }  > data AT > text    .bss :    {        .......    }  > data    (injen-d @ Apr 9 2008, 19:43)

тоже работает, но результат тот же: _app_end == _etext sad.gif

Пожалуй лучше использовать приведенный мной вариант:
Код
SECTIONS
{
         ......
   _size_prog = _etext +(_edata -0x100);
}


--------------------
- Бендер, ты же робот, зачем тебе пить пиво?
- Незачем! Я могу бросить в любой момент!
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 10 2008, 14:22
Сообщение #8


Гуру
******

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



Цитата(injen-d @ Apr 9 2008, 22:26) *
тоже работает, но результат тот же: _app_end == _etext sad.gif
Вы знаете, я проверил. Да, получаю такой же результат. И в avr-gcc и в 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
amw
сообщение Apr 10 2008, 17:23
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 601
Регистрация: 22-09-05
Из: Kharkov
Пользователь №: 8 847



Цитата(Сергей Борщ @ Apr 10 2008, 17:22) *
Вы знаете, я проверил. Да, получаю такой же результат. И в avr-gcc и в arm-elf-gcc. Но ведь перед написанием того ответа я легко получил то, что нужно! Пойду домой, попробую повторить фокус. Если получится - буду искать причину такого странного поведения.

Просто поставте последней секцию типа такой.
Код
    .finish :
    {
        _app_end = .;
    } > FLASH


--------------------
- А мораль отсюда такова: всякому овощу свое время. Или, хочешь, я это сформулирую попроще: никогда не думай, что ты иная, чем могла бы быть иначе, чем будучи иной в тех случаях, когда иначе нельзя не быть.
© Lewis Carroll. Alice's adventures in wonderland.
Go to the top of the page
 
+Quote Post
injen-d
сообщение Apr 10 2008, 18:11
Сообщение #10


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

Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250



Цитата
Просто поставте последней секцию типа такой.

Проверил, работает правильно.
Код
.finish :
  {
      _size_prog = .;
  } > text
}

Спасибо за подсказки, пожалуй, буду использовать этот вариант.

Добавлю еще, что если использовать файл скрипта из WinAVR и просто добавить в конце:
Код
.finish :
  {
      _size_prog = .;
  } > text
}

то заначение _size_prog все равно будет неверным, чтобы это исправить необходимо изменить описание секции .data как указал Сергей Борщ:
вместо
Код
.data      : AT (ADDR (.text) + SIZEOF (.text))
  {
     PROVIDE (__data_start = .);
    *(.data)
    *(.data*)
    *(.rodata)  /* We need to include .rodata here if gcc is used */
    *(.rodata*) /* with -fdata-sections.  */
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
     _edata = .;
     PROVIDE (__data_end = .);
  }  > data

нужно сделать:
Код
.data :
  {
     PROVIDE (__data_start = .);
    *(.data)
    *(.data*)
    *(.rodata)  /* We need to include .rodata here if gcc is used */
    *(.rodata*) /* with -fdata-sections.  */
    *(.gnu.linkonce.d*)
    . = ALIGN(2);
     _edata = .;
     PROVIDE (__data_end = .);
  }  > data AT > text


--------------------
- Бендер, ты же робот, зачем тебе пить пиво?
- Незачем! Я могу бросить в любой момент!
Go to the top of the page
 
+Quote Post
antiwin
сообщение May 25 2009, 08:07
Сообщение #11


Участник
*

Группа: Новичок
Сообщений: 22
Регистрация: 20-05-09
Пользователь №: 49 303



AT (ADDR (.text) + SIZEOF (.text))

Народ, разясните смысл этих строк, SIZEOF вроде понятно-это размер секции, тогда ADDR-это начало? и что это за оператор AT?.
И еще, в WinAvr есть папка с man, как вот эти man прочесть? Я думаю, что масса вопросов сразу бы отпала.
wassat.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 25 2009, 08:39
Сообщение #12


Гуру
******

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



Цитата(antiwin @ May 25 2009, 11:07) *
Народ, разясните смысл этих строк, SIZEOF вроде понятно-это размер секции, тогда ADDR-это начало? и что это за оператор AT?.
GNU ld: Output Section Description
Цитата(antiwin @ May 25 2009, 11:07) *
И еще, в WinAvr есть папка с man, как вот эти man прочесть?
Хороший вопрос. в *никсах для этого есть утилита man. В msys/mingw я такой не нашел.


--------------------
На любой вопрос даю любой ответ
"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

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

 


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


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