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

 
 
 
Reply to this topicStart new topic
> Проблема с константами в классе., В iar всё работает а в GCC нет...
inco
сообщение May 19 2010, 11:57
Сообщение #1


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

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
klen
сообщение May 19 2010, 14:36
Сообщение #2


бессмертным стать можно тремя способами
*****

Группа: Свой
Сообщений: 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++ сгенерит табличку с адресами всех конструкторов глобальных статических объектов
cool.gif линкер положит ее в секцию .ctors
c) ну а уж crt код вызовет по таблице все конструкторы.
e) все работает и мы счастливы

в сдучае с иаром скорее всего это уже сделано зарание.

упражнение для закрепления материала: аналогичными рассуждениями проработать вопрос деструкторы
контрольный вопрос; почему на деструктоы можно забить большой болт с дюймовой резбой?

и еще, я уже если не изменяет память принимал участие в разжовывании этого. поиск рулит. если у Вас окажется другой косяг - тады извиняюсь, будем курить его.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение May 19 2010, 15:31
Сообщение #3


фанат дивана
******

Группа: Свой
Сообщений: 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.*)
...

Без этого глобальные объекты не инициализировались.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
inco
сообщение May 19 2010, 16:13
Сообщение #4


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

Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984



Спасибо за информацию! Буду переваривать! Пока ничего не понял про конструкторы!

Объекты да глобальные.

По результатам отпишусь. Проверю только завтра на работе.

На всякий случай привожу свой скрипт линкера:

__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
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение May 19 2010, 18:31
Сообщение #5


фанат дивана
******

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



Цитата(inco @ May 19 2010, 22:13) *
Стартап брал стандартный из библиотеки stm32 версии 3.2


Этот стартап совершенно точно не вызывает конструкторы глобальных объектов.
Пример рабочего стартапа и линкерного скрипта для C++ можете посмотреть вот в этом примере из scmRTOS.
Проверено с kgp и codesourcery.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
inco
сообщение May 20 2010, 06:15
Сообщение #6


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

Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984



Спасибо за помощь!!!

Всё получилось! Собрал гибрида стартапа из scmRtos и других примеров под себя и переделал скрипт линкера. Теперь вроде всё на месте, конструкторы работают. Вот только не понятно, как это всё работает, где бы про это почитать?

Интересует как происходит процесс инициализации конструкторов в деталях. Если со стартом сишной программы всё понятно, то с плюсами получается пробел в понимании. Вообще где почитать чем отличается инициализация сишной программы от плюсовой? Не люблю чего-то не понимать.

И ещё попутно вопрос по этой строке:

uart(const uint8_t n, const uint8_t c) : num(n), channel( c) { // Конструктор

параметры после двоеточия num(n), channel( c) не понимаю.
То есть, что происходит смысл понятен, присваивается значение константам, но вот как до этого додуматься не понятно! Я просто нашел этот способ инициализации констант в инете, а где про это почитать не нашел. Вроде по плюсам там должен быть предок а не переменные?!

Если вопросы глупые прошу сильно не пинать, на плюсах первый раз решил написать прогу.
До этого всё больше на чистом си. А теперь понравилось! Оказывается такая вещь... smile.gif
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение May 20 2010, 10:44
Сообщение #7


фанат дивана
******

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



Цитата(inco @ May 20 2010, 12:15) *
Всё получилось!

Аминьsmile.gif
Цитата
Интересует как происходит процесс инициализации конструкторов в деталях.

При помощи вызова оныхsmile.gif Аналогия с си - прямая. Если в си есть статическая переменная, то она инициализируется в стартапе. Если в C++ есть глобальный объект, то он точно так же инициализируется в стартапе. За инициализацию отвечает конструктор. Поэтому он вызывается из стартапа.
Цитата
Вообще где почитать

Читать естественно "Язык программирования С++", Бьерн Страуструп. Третье издание.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 20 2010, 19:43
Сообщение #8


Гуру
******

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



Цитата(AHTOXA @ May 20 2010, 13:44) *
При помощи вызова оныхsmile.gif Аналогия с си - прямая. Если в си есть статическая переменная, то она инициализируется в стартапе. Если в C++ есть глобальный объект, то он точно так же инициализируется в стартапе. За инициализацию отвечает конструктор. Поэтому он вызывается из стартапа.
Более "на пальцах": Указатели на конструкторы помещаются в секцию .ctors, а код в стартапе проходит эту секцию, вызывая функции по считанному указателю. Если указатель равен нулю - баста. "Ловкость рук и никакого мошенничества".

Можно в скрипте линкера отсортировать эти указатели по именам объектов или именам файлов, обеспечив некоторый определенный порядок вызова конструкторов, но Страуструп такого не обещал.


--------------------
На любой вопрос даю любой ответ
"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
inco
сообщение May 20 2010, 20:10
Сообщение #9


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

Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984



Спасибо просветили! Скачал третье издание Страуструпа, все непонятности там нашёл! Да! Мир сильно изменился за это время. Тот что у меня на полке был (второе издание от 1993 года) там этого не было! Теперь на счёт языка всё стало ясно!

Теперь возникла другая проблема. Опять где-то, что-то не склеилось. В озу программа заработала полностью, а вот в пзу не хочет. Линкер разместил какие-то константы по адресу озу и J-Flash ARM не хочет шить пзу говорит недопустимый сегмент. Посмотрел мап файл, да действительно он туда распределил секцию дата:
.data 0x20000000 0x18
0x20000000 . = ALIGN (0x4)
0x20000000 _sdata = .
Вот только какого хрена она попадает в бинарный файл (который из-за этого получается размером с пол гиктара) пока не пойму. С кодом для озу при этом всё в порядке и бинарник размером 13К.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 20 2010, 20:49
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение May 21 2010, 04:42
Сообщение #11


фанат дивана
******

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



Цитата(Сергей Борщ @ May 21 2010, 01:43) *
Более "на пальцах": Указатели на конструкторы помещаются в секцию .ctors

В секцию .init_array! maniac.gif smile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
inco
сообщение May 21 2010, 06:02
Сообщение #12


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

Группа: Свой
Сообщений: 161
Регистрация: 26-08-05
Из: Российская Империя
Пользователь №: 7 984



Спасибо ещё раз!!!

Дали направление поиска.

Вот выкладываю свой стартап и скрипт линкера может глянете, если не затруднит!
А то сразу въехать в линкерный скрипт тяжело.

На счёт кнопки, большое спасибо. Не видел. Помню раньше надо было теги ставить code, перед тем как вставлять код. Полез почитать правила форума, специально перед отправкой кода, в правилах ничего про это не нашел! А про кнопку ни вжизь не догадался бы! Надо это дело как-то в правилах форума акцентировать!!!
Прикрепленные файлы
Прикрепленный файл  link_startup.zip ( 4.55 килобайт ) Кол-во скачиваний: 15
 
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение May 21 2010, 06:38
Сообщение #13


фанат дивана
******

Группа: Свой
Сообщений: 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 smile.gif )


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
inco
сообщение May 21 2010, 07:48
Сообщение #14


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

Группа: Свой
Сообщений: 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 smile.gif )


Да это было оно! Всё работает! Ура !!! И во флеше и в озу!
Почему-то подумал что этот сегмент данных надо размещать в озу.

СПАСИБО !!!
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 00:05
Рейтинг@Mail.ru


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