Перейти к содержанию
    

GNU linker, .rodata and .data sections

Коллеги,

 

Часть глобальных данных хочу инициализировать ещё на этапе объявления. Ну там 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) как страшный сон и вредные советы.

Вот такой кусочек прекрасно работает:

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;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за совет.

 

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

 

 

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

*pDst++ = *pSrc++;

 

То почему бы не иметь опцию, которая бы сразу совмещала данные и их заполнение по одному адресу? Или такой опции не существует?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так у вас тоже под константы место выделяется отдельно, а для данных которыми инициализируются этими константами отдельно.
Да, все верно. А у вас что, и код и данные грузятся перед исполнением в ОЗУ какой-то сторонней запускалкой? Тогда просто убрать AT > ROM и данные будут расположены сразу по адресам .data, а копирование будет не нужно.

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...