Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: GNU linker, .rodata and .data sections
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > Программирование
RCray
Коллеги,

Часть глобальных данных хочу инициализировать ещё на этапе объявления. Ну там int32_t a[5] = {1, 2, 3, 4, 5}; А всю остальную часть глобальных данных хочу обнулить. Моя проблема в том, что секция с данными {1, 2, 3, 4, 5} и a[5] оказываются отдельно в разных секциях .rodata и .data соответсвенно. Существует ли какой-то способ сэкономить память и сразу их объеденить ещё на этапе линкования? Спасибо.


Сейчас использую такое описание в *.ld файле для линкера:

Код
MEMORY
{
   ...
   ...
   IntCodeRAM   (rx) : ORIGIN = 0x00080000, LENGTH = 128k
   IntDataRAM   (rw) : ORIGIN = 0x20000000, LENGTH = 112k
   ...
   ...
}

PROVIDE (initStart = _etext);

   /*******************************************/
   /* .rodata section for read-only data (constants) */

  .rodata . :
  {
    *(.rodata)
    *(.rodata.*)    
  . = ALIGN(4);
  _etext = .;
  PROVIDE (etext = .);

  } >IntCodeRAM


  /*******************************************/
  /* .data section for initialized data */

  .data  : AT (_etext)
  {
    /* used for initialized data */
    dataStart = .;
    PROVIDE (dataStart = .);
    *(.data)
       *(.data.*)    
      *(.gnu.linkonce.d*)

    SORT(CONSTRUCTORS)
    dataEnd = .;
    PROVIDE (dataEnd = .);
  } >IntDataRAM
  . = ALIGN(4);

  _edata = .;
   PROVIDE (edata = .);



    /*******************************************/
    /* .bss section for uninitialized data */
  .bss :
  {

    bssStart = .;
    bssStart = .;
    *(.bss)
    *(.gnu.linkonce.b*)    
    
    . = ALIGN(4);
    bssEnd = .;
        
  } >IntDataRAM


А потом для обнуления или инициализации глобальных данных константами использую в исходниках следующий код
Код
    
    /* initialize .data segment */
    src = &initStart;
    for(dst = &dataStart; dst < &dataEnd; )
    {
        *dst++ = *src++;
    }

    /* Zero fill the .bss segment. */
    for(dst = &bssStart; dst < &bssEnd; )
    {
        *dst++ = 0;
    }
Сергей Борщ
Как-то у вас очень сложно. В .rodata идут константы, а ваши a[] и {1,2,3,4,5} должны попасть в .data. А начальные значения .data {1,2,3,4,5} линкер поместил во флеш надо использовать конструкцию > IntDataRAM AT > IntCodeRAM. И забудьте конструкцию .data : AT (_etext) как страшный сон и вредные советы.
Вот такой кусочек прекрасно работает:
CODE
MEMORY
{
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}
SECTIONS
{
.......
.data :
{
. = ALIGN(4);
_sdata = .; /* start of .data label */
*(.data)
*(.data.*)
. = ALIGN(4);
_edata = .; /* end of .data label */
} > RAM AT > ROM
_sidata = LOADADDR(.data); /* start of initialized data label */

/* .bss section - uninitialized data */
.bss (NOLOAD):
{
. = ALIGN(4);
_sbss = .; /* start of .bss label (for startup) */
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* end of .bss label (for startup) */
_end = .; /* end of used ram (start of free memory, for malloc) */
__end = .; /* the same */
} > RAM


extern uint32_t _sidata[];
extern uint32_t _sdata[];
extern uint32_t _edata[];
extern uint32_t _sbss[];
extern uint32_t _ebss[];

static inline __attribute__((always_inline))
void __Init_Data(void)
{
uint32_t *pSrc = _sidata;

for(uint32_t * pDst = _sdata; pDst < _edata; )
*pDst++ = *pSrc++;

for(uint32_t * pDst = _sbss; pDst < _ebss; )
*pDst++ = 0;
}
RCray
Спасибо за совет.

Так у вас тоже под константы место выделяется отдельно, а для данных которыми инициализируются этими константами отдельно. И если и вы, и я в итоге используем в любом случае строчки вида:


for(uint32_t * pDst = _sdata; pDst < _edata; )
*pDst++ = *pSrc++;

То почему бы не иметь опцию, которая бы сразу совмещала данные и их заполнение по одному адресу? Или такой опции не существует?
Сергей Борщ
QUOTE (RCray @ Mar 26 2012, 21:44) *
Так у вас тоже под константы место выделяется отдельно, а для данных которыми инициализируются этими константами отдельно.
Да, все верно. А у вас что, и код и данные грузятся перед исполнением в ОЗУ какой-то сторонней запускалкой? Тогда просто убрать AT > ROM и данные будут расположены сразу по адресам .data, а копирование будет не нужно.

Этот же скрипт полагает, что программа находится во флеше и исполняется после включения питания из флеша. А данные {1,2,3,4,5} в ОЗУ после включения питания должны откуда-то как-то появится, они ведь теряются после выключения питания, вот они и копируются этим циклом, а копироваться они должны из флеша, куда начальные значения и помещаются конструкцией AT > ROM.

А если вы объявите данные как int32_t const a[5] = {1, 2, 3, 4, 5}; то они попадут в секцию .rodata и вот ее можно смело класть в выходную секцию .text, ибо компилятор будет следить за тем, чтобы вы использовали эти данные только для чтения и поэтому они могут лежать во флеше.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.