|
|
  |
Проблема с константами в классе., В iar всё работает а в GCC нет... |
|
|
|
May 19 2010, 11:57
|
Частый гость
 
Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984

|
Есть некий базовый класс:
class uart { protected: const uint8_t num; const uint8_t channel; volatile uint32_t time; uint8_t rxCount; uint8_t echoMode; __uartState state; uint32_t tx_pointer; uint32_t rx_pointer; uint32_t size; uint32_t txSize; uint8_t rxEchoSize; uint8_t error[2]; uint16_t crc; public: uart(const uint8_t n, const uint8_t c) : num(n), channel( c) { // Конструктор time = tx_pointer = rx_pointer = size = 0; error[0] = error[1] = 0; }; ...
есть от него наследник:
class mco_uart : public uart { public: uint8_t buf[2][MCO_BUFF_SIZE]; mco_uart(const uint8_t n, const uint8_t c) : uart (n, c) {}; // Конструктор ...
создаю экземпляры класса:
mco_uart extUart[EXTUART_NUM] = { mco_uart(0, 4 << 4), mco_uart(0, 5 << 4), mco_uart(0, 6 << 4), mco_uart(0, 7 << 4), mco_uart(1, 4 << 4), mco_uart(1, 5 << 4), mco_uart(1, 6 << 4), mco_uart(0, 1 << 4), mco_uart(0, 2 << 4), mco_uart(0, 3 << 4), mco_uart(1, 0 << 4), mco_uart(1, 1 << 4), mco_uart(1, 2 << 4), mco_uart(1, 3 << 4) };
В результате переменные num и channel равны 0. В иаре всё работает то есть значения переменным присваивается правильно, а в gcc присваивания нет. Что я делаю не так? На плюсах пишу первый раз, до этого писал только на чистом C. Хочется перейти на gcc и не получается! Компилятор от клёна kgp_arm_eabi_20100509
|
|
|
|
|
May 19 2010, 14:36
|

бессмертным стать можно тремя способами
    
Группа: Свой
Сообщений: 1 405
Регистрация: 9-05-06
Из: Москва
Пользователь №: 16 912

|
Цитата(inco @ May 19 2010, 15:57)  В результате переменные num и channel равны 0. В иаре всё работает то есть значения переменным присваивается правильно, а в gcc присваивания нет. Что я делаю не так? На плюсах пишу первый раз, до этого писал только на чистом C. Хочется перейти на gcc и не получается! Компилятор от клёна kgp_arm_eabi_20100509 mco_uart extUart[EXTUART_NUM] глобальный объект или на стеке ? конструкторы статических объектов вызываются? давайте кусок кода который это воспроизведет, без лишних деталей. я не телепат но скорее всего просто конструкторы статических глобальных объектов не вызываются. чтобы это работало в скрипт линкера долны быть добавлены Код /* .ctors .dtors are used for c++ constructors/destructors */ .ctors : { PROVIDE(__ctors_start__ = .); KEEP(*(SORT(.ctors.*))) KEEP(*(.ctors)) PROVIDE(__ctors_end__ = .); } >ROM .dtors : { PROVIDE(__dtors_start__ = .); KEEP(*(SORT(.dtors.*))) KEEP(*(.dtors)) PROVIDE(__dtors_end__ = .); } >ROM в сило того что сами по себе в коде конструкторы статических глобальных объекто не вызываются линкер их нахрен выкидывает дкумая что это лишний код чтоб работал С++ нада добавить вышеприведенную хрень в скрипт линкео, она говорит линкеру что функции конструкторы нужны и сувать их в отдельные секции, хотя вариантов может быть куча - это всеголиш так принято. далее ктото должен вызвать эти конструкторы до вызова main. это обычно принято делать в crt коде. вставте полсле инициализации данных в crt следующий код; Код DR R0, =__ctors_start__ LDR R1, =__ctors_end__ ctor_loop: CMP R0, R1 BEQ ctor_end LDR R2, [R0], #4 STMFD SP!, {R0-R1} MOV LR, PC MOV PC, R2 LDMFD SP!, {R0-R1} B ctor_loop ctor_end: a)g++ сгенерит табличку с адресами всех конструкторов глобальных статических объектов  линкер положит ее в секцию .ctors c) ну а уж crt код вызовет по таблице все конструкторы. e) все работает и мы счастливы в сдучае с иаром скорее всего это уже сделано зарание. упражнение для закрепления материала: аналогичными рассуждениями проработать вопрос деструкторы контрольный вопрос; почему на деструктоы можно забить большой болт с дюймовой резбой? и еще, я уже если не изменяет память принимал участие в разжовывании этого. поиск рулит. если у Вас окажется другой косяг - тады извиняюсь, будем курить его.
|
|
|
|
|
May 19 2010, 15:31
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(klen @ May 19 2010, 20:36)  Код /* .ctors .dtors are used for c++ constructors/destructors */ .ctors : { PROVIDE(__ctors_start__ = .); KEEP(*(SORT(.ctors.*))) KEEP(*(.ctors)) PROVIDE(__ctors_end__ = .); } >ROM Точняк! Только после перехода на eabi конструкторы хранятся в .init_array: Код __ctors_start__ = .; KEEP(SORT(*)(.init_array)) __ctors_end__ = .; Вот так точно работает. 2 inco. Ещё у меня был вариант с ключом -fdata-sections. Многие примеры загрузочных скриптов, имеющиеся в интернете это не учитывали. Надо добавить *(.bss.*) в bss: Код .bss : { . = ALIGN(4); _sbss = .; *(.bss) *(.bss.*) ... Без этого глобальные объекты не инициализировались.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 19 2010, 18:31
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(inco @ May 19 2010, 22:13)  Стартап брал стандартный из библиотеки stm32 версии 3.2 Этот стартап совершенно точно не вызывает конструкторы глобальных объектов. Пример рабочего стартапа и линкерного скрипта для C++ можете посмотреть вот в этом примере из scmRTOS. Проверено с kgp и codesourcery.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 20 2010, 06:15
|
Частый гость
 
Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984

|
Спасибо за помощь!!! Всё получилось! Собрал гибрида стартапа из scmRtos и других примеров под себя и переделал скрипт линкера. Теперь вроде всё на месте, конструкторы работают. Вот только не понятно, как это всё работает, где бы про это почитать? Интересует как происходит процесс инициализации конструкторов в деталях. Если со стартом сишной программы всё понятно, то с плюсами получается пробел в понимании. Вообще где почитать чем отличается инициализация сишной программы от плюсовой? Не люблю чего-то не понимать. И ещё попутно вопрос по этой строке: uart(const uint8_t n, const uint8_t c) : num(n), channel( c) { // Конструктор параметры после двоеточия num(n), channel( c) не понимаю. То есть, что происходит смысл понятен, присваивается значение константам, но вот как до этого додуматься не понятно! Я просто нашел этот способ инициализации констант в инете, а где про это почитать не нашел. Вроде по плюсам там должен быть предок а не переменные?! Если вопросы глупые прошу сильно не пинать, на плюсах первый раз решил написать прогу. До этого всё больше на чистом си. А теперь понравилось! Оказывается такая вещь...
|
|
|
|
|
May 20 2010, 10:44
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(inco @ May 20 2010, 12:15)  Всё получилось! Аминь  Цитата Интересует как происходит процесс инициализации конструкторов в деталях. При помощи вызова оных  Аналогия с си - прямая. Если в си есть статическая переменная, то она инициализируется в стартапе. Если в C++ есть глобальный объект, то он точно так же инициализируется в стартапе. За инициализацию отвечает конструктор. Поэтому он вызывается из стартапа. Цитата Вообще где почитать Читать естественно "Язык программирования С++", Бьерн Страуструп. Третье издание.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 20 2010, 19:43
|

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

|
Цитата(AHTOXA @ May 20 2010, 13:44)  При помощи вызова оных  Аналогия с си - прямая. Если в си есть статическая переменная, то она инициализируется в стартапе. Если в C++ есть глобальный объект, то он точно так же инициализируется в стартапе. За инициализацию отвечает конструктор. Поэтому он вызывается из стартапа. Более "на пальцах": Указатели на конструкторы помещаются в секцию .ctors, а код в стартапе проходит эту секцию, вызывая функции по считанному указателю. Если указатель равен нулю - баста. "Ловкость рук и никакого мошенничества". Можно в скрипте линкера отсортировать эти указатели по именам объектов или именам файлов, обеспечив некоторый определенный порядок вызова конструкторов, но Страуструп такого не обещал.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 20 2010, 20:49
|

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

|
Цитата(inco @ May 20 2010, 23:10)  Линкер разместил какие-то константы по адресу озу и J-Flash ARM не хочет шить пзу говорит недопустимый сегмент. Посмотрел мап файл, да действительно он туда распределил секцию дата: .data 0x20000000 0x18 0x20000000 . = ALIGN (0x4) 0x20000000 _sdata = . Вот только какого хрена она попадает в бинарный файл (который из-за этого получается размером с пол гиктара) пока не пойму. Можно предположить, что некорректно написан скрипт линкера. Дело в том, что по стандартам gcc секция .data - инициализированные константы. Для упрощения процесса инициализации копия всех инициализированных значений хранится во флеше и при старте программы просто "тупо копируется" в ОЗУ. Для корректного выполнения этой операции скрипт линкера должен выглядеть примерно так: Код /* .data section which is used for initialized data */ .data : /* place init values immediatly after .text section */ { _data = .; *(.ramfunc*) *(.data*)
_edata = .; _data_image = LOADADDR(.data);
PROVIDE (edata = .); } > RAM AT > ROM То есть разместить выходную секцию .data в регион RAM (Virtual Memory Address, VMA), но их значения положить в регион ROM (в Loadable Memory Address, LMA). В вашем скрипте магические слова "AT > ROM" скорее всего отсутствуют, и начальные значения остаются на своих реальных адресах. P.S. И старайтесь оформлять исходники используя кнопку
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 21 2010, 06:02
|
Частый гость
 
Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984

|
Спасибо ещё раз!!! Дали направление поиска. Вот выкладываю свой стартап и скрипт линкера может глянете, если не затруднит! А то сразу въехать в линкерный скрипт тяжело. На счёт кнопки, большое спасибо. Не видел. Помню раньше надо было теги ставить code, перед тем как вставлять код. Полез почитать правила форума, специально перед отправкой кода, в правилах ничего про это не нашел! А про кнопку ни вжизь не догадался бы! Надо это дело как-то в правилах форума акцентировать!!!
|
|
|
|
|
May 21 2010, 06:38
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(inco @ May 21 2010, 12:02)  Вот выкладываю свой стартап и скрипт линкера может глянете, если не затруднит! Код .text.align : { . = ALIGN(8); _etext = .; _sidata = _etext; /* start of initialized data label */ } >RAM Вот это надо вернуть во FLASH. (Как и было в исходном скрипте из scmRTOS  )
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
May 21 2010, 07:48
|
Частый гость
 
Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984

|
Цитата(AHTOXA @ May 21 2010, 09:38)  Код .text.align : { . = ALIGN(8); _etext = .; _sidata = _etext; /* start of initialized data label */ } >RAM Вот это надо вернуть во FLASH. (Как и было в исходном скрипте из scmRTOS  ) Да это было оно! Всё работает! Ура !!! И во флеше и в озу! Почему-то подумал что этот сегмент данных надо размещать в озу. СПАСИБО !!!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|