inco 1 19 мая, 2010 Опубликовано 19 мая, 2010 · Жалоба Есть некий базовый класс: 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 19 мая, 2010 Опубликовано 19 мая, 2010 · Жалоба В результате переменные 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++ сгенерит табличку с адресами всех конструкторов глобальных статических объектов B) линкер положит ее в секцию .ctors c) ну а уж crt код вызовет по таблице все конструкторы. e) все работает и мы счастливы в сдучае с иаром скорее всего это уже сделано зарание. упражнение для закрепления материала: аналогичными рассуждениями проработать вопрос деструкторы контрольный вопрос; почему на деструктоы можно забить большой болт с дюймовой резбой? и еще, я уже если не изменяет память принимал участие в разжовывании этого. поиск рулит. если у Вас окажется другой косяг - тады извиняюсь, будем курить его. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 19 мая, 2010 Опубликовано 19 мая, 2010 · Жалоба /* .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.*) ... Без этого глобальные объекты не инициализировались. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 19 мая, 2010 Опубликовано 19 мая, 2010 · Жалоба Спасибо за информацию! Буду переваривать! Пока ничего не понял про конструкторы! Объекты да глобальные. По результатам отпишусь. Проверю только завтра на работе. На всякий случай привожу свой скрипт линкера: __Stack_Size = 1024 ; PROVIDE ( _Stack_Size = __Stack_Size ); __Stack_Init = _estack - __Stack_Size; /*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/ PROVIDE ( _Stack_Init = __Stack_Init ); /* There will be a link error if there is not this amount of RAM free at the end. */ _Minimum_Stack_Size = 0x100; /* include the memory spaces definitions sub-script */ /* Linker subscript for STM32F10x definitions with 512K Flash and 64K RAM */ /* Memory Spaces Definitions */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 48K } /* higher address of the user mode stack */ _estack = 0x2000c000; /* include the sections management sub-script for FLASH mode */ /* Sections Definitions */ SECTIONS { /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >SRAM /* the program code is stored in the .text section, which goes to Flash */ .text : { . = ALIGN(4); *(.text .text.* .gnu.linkonce.t.*) *(.plt) *(.gnu.warning) *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.ARM.extab* .gnu.linkonce.armextab.*) *(.gcc_except_table) } >SRAM .checksum 0x20005ffe : { . = ALIGN(2); KEEP(*(.checksum)) /* Checksum code */ } >SRAM .eh_frame_hdr : ALIGN (4) { KEEP (*(.eh_frame_hdr)) } >SRAM .eh_frame : ALIGN (4) { KEEP (*(.eh_frame)) } >SRAM /* .ARM.exidx is sorted, so has to go in its own output section. */ __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >SRAM __exidx_end = .; .rodata : ALIGN (4) { *(.rodata .rodata.* .gnu.linkonce.r.*) . = ALIGN(4); KEEP(*(.init)) . = ALIGN(4); __preinit_array_start = .; KEEP (*(.preinit_array)) __preinit_array_end = .; . = ALIGN(4); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; . = ALIGN(4); KEEP(*(.fini)) . = ALIGN(4); __fini_array_start = .; KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) __fini_array_end = .; . = ALIGN(4); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*crtend.o(.ctors)) . = ALIGN(4); KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*crtend.o(.dtors)) . = ALIGN(4); _etext = .; /* This is used by the startup in order to initialize the .data secion */ _sidata = _etext; } >SRAM /* This is the initialized data section The program executes knowing that the data is in the RAM but the loader puts the initial values in the FLASH (inidata). It is one task of the startup to copy the initial values from FLASH to RAM. */ .data : AT ( _sidata ) { . = ALIGN(4); /* This is used by the startup in order to initialize the .data secion */ _sdata = . ; KEEP(*(.jcr)) *(.got.plt) *(.got) *(.shdata) *(.data .data.* .gnu.linkonce.d.*) . = ALIGN(4); /* This is used by the startup in order to initialize the .data secion */ _edata = . ; } >SRAM /* This is the uninitialized data section */ .bss : { . = ALIGN(4); /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; *(.shbss) *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) . = ALIGN(4); /* This is used by the startup in order to initialize the .bss secion */ _ebss = . ; } >SRAM PROVIDE ( end = _ebss ); PROVIDE ( _end = _ebss ); /* This is the user stack section This is just to check that there is enough RAM left for the User mode stack It should generate an error if it's full. */ ._usrstack : { . = ALIGN(4); _susrstack = . ; . = . + _Minimum_Stack_Size ; . = ALIGN(4); _eusrstack = . ; } >SRAM /* after that it's only debugging information. */ /* remove the debugging information from the standard libraries */ DISCARD : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } /DISCARD/ : { *(.note.GNU-stack) } } Стартап брал стандартный из библиотеки stm32 версии 3.2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 19 мая, 2010 Опубликовано 19 мая, 2010 · Жалоба Стартап брал стандартный из библиотеки stm32 версии 3.2 Этот стартап совершенно точно не вызывает конструкторы глобальных объектов. Пример рабочего стартапа и линкерного скрипта для C++ можете посмотреть вот в этом примере из scmRTOS. Проверено с kgp и codesourcery. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 20 мая, 2010 Опубликовано 20 мая, 2010 · Жалоба Спасибо за помощь!!! Всё получилось! Собрал гибрида стартапа из scmRtos и других примеров под себя и переделал скрипт линкера. Теперь вроде всё на месте, конструкторы работают. Вот только не понятно, как это всё работает, где бы про это почитать? Интересует как происходит процесс инициализации конструкторов в деталях. Если со стартом сишной программы всё понятно, то с плюсами получается пробел в понимании. Вообще где почитать чем отличается инициализация сишной программы от плюсовой? Не люблю чего-то не понимать. И ещё попутно вопрос по этой строке: uart(const uint8_t n, const uint8_t c) : num(n), channel( c) { // Конструктор параметры после двоеточия num(n), channel( c) не понимаю. То есть, что происходит смысл понятен, присваивается значение константам, но вот как до этого додуматься не понятно! Я просто нашел этот способ инициализации констант в инете, а где про это почитать не нашел. Вроде по плюсам там должен быть предок а не переменные?! Если вопросы глупые прошу сильно не пинать, на плюсах первый раз решил написать прогу. До этого всё больше на чистом си. А теперь понравилось! Оказывается такая вещь... :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 20 мая, 2010 Опубликовано 20 мая, 2010 · Жалоба Всё получилось! Аминь:) Интересует как происходит процесс инициализации конструкторов в деталях. При помощи вызова оных:) Аналогия с си - прямая. Если в си есть статическая переменная, то она инициализируется в стартапе. Если в C++ есть глобальный объект, то он точно так же инициализируется в стартапе. За инициализацию отвечает конструктор. Поэтому он вызывается из стартапа. Вообще где почитать Читать естественно "Язык программирования С++", Бьерн Страуструп. Третье издание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 мая, 2010 Опубликовано 20 мая, 2010 · Жалоба При помощи вызова оных:) Аналогия с си - прямая. Если в си есть статическая переменная, то она инициализируется в стартапе. Если в C++ есть глобальный объект, то он точно так же инициализируется в стартапе. За инициализацию отвечает конструктор. Поэтому он вызывается из стартапа.Более "на пальцах": Указатели на конструкторы помещаются в секцию .ctors, а код в стартапе проходит эту секцию, вызывая функции по считанному указателю. Если указатель равен нулю - баста. "Ловкость рук и никакого мошенничества". Можно в скрипте линкера отсортировать эти указатели по именам объектов или именам файлов, обеспечив некоторый определенный порядок вызова конструкторов, но Страуструп такого не обещал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 20 мая, 2010 Опубликовано 20 мая, 2010 · Жалоба Спасибо просветили! Скачал третье издание Страуструпа, все непонятности там нашёл! Да! Мир сильно изменился за это время. Тот что у меня на полке был (второе издание от 1993 года) там этого не было! Теперь на счёт языка всё стало ясно! Теперь возникла другая проблема. Опять где-то, что-то не склеилось. В озу программа заработала полностью, а вот в пзу не хочет. Линкер разместил какие-то константы по адресу озу и J-Flash ARM не хочет шить пзу говорит недопустимый сегмент. Посмотрел мап файл, да действительно он туда распределил секцию дата: .data 0x20000000 0x18 0x20000000 . = ALIGN (0x4) 0x20000000 _sdata = . Вот только какого хрена она попадает в бинарный файл (который из-за этого получается размером с пол гиктара) пока не пойму. С кодом для озу при этом всё в порядке и бинарник размером 13К. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 мая, 2010 Опубликовано 20 мая, 2010 · Жалоба Линкер разместил какие-то константы по адресу озу и 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. И старайтесь оформлять исходники используя кнопку Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 21 мая, 2010 Опубликовано 21 мая, 2010 · Жалоба Более "на пальцах": Указатели на конструкторы помещаются в секцию .ctors В секцию .init_array! :maniac: :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 21 мая, 2010 Опубликовано 21 мая, 2010 · Жалоба Спасибо ещё раз!!! Дали направление поиска. Вот выкладываю свой стартап и скрипт линкера может глянете, если не затруднит! А то сразу въехать в линкерный скрипт тяжело. На счёт кнопки, большое спасибо. Не видел. Помню раньше надо было теги ставить code, перед тем как вставлять код. Полез почитать правила форума, специально перед отправкой кода, в правилах ничего про это не нашел! А про кнопку ни вжизь не догадался бы! Надо это дело как-то в правилах форума акцентировать!!! link_startup.zip Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 21 мая, 2010 Опубликовано 21 мая, 2010 · Жалоба Вот выкладываю свой стартап и скрипт линкера может глянете, если не затруднит! .text.align : { . = ALIGN(8); _etext = .; _sidata = _etext; /* start of initialized data label */ } >RAM Вот это надо вернуть во FLASH. (Как и было в исходном скрипте из scmRTOS :) ) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
inco 1 21 мая, 2010 Опубликовано 21 мая, 2010 · Жалоба .text.align : { . = ALIGN(8); _etext = .; _sidata = _etext; /* start of initialized data label */ } >RAM Вот это надо вернуть во FLASH. (Как и было в исходном скрипте из scmRTOS :) ) Да это было оно! Всё работает! Ура !!! И во флеше и в озу! Почему-то подумал что этот сегмент данных надо размещать в озу. СПАСИБО !!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться