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

GCC, размещение переменной по фиксированному адресу

Захотелось мне разместить переменную в самом конце используемой области флеш - после секций .text и .data.

 

И я не придумал ничего лучшего, как в скрипте линкера написать

/*выше - секция .data */

    /* конец данных во флеш - кладём сюда контрольную сумму */
    .CheckSum :
        /*AT ( _sidata + SIZEOF ( .data ) )*/
        AT ( _sidata + (_edata - _sdata) )
    {
        . = ALIGN(4);
        KEEP(*(.CheckSum))
    } > FLASH

/*ниже - секция .bss*/

(пробовал оба варианта AT(), работает одинаково)

 

__attribute__ ((section(".CheckSum")))
const uint32_t gCoreChksum = 0xAABBCCDD;

 

 

И получил следующее:

- в map-файле моя переменная имеет тот же адрес, что и начало .data

- в программе взятие адреса также возвращает адрес начала .data

- в скомпилированном бинарнике переменную явно видно в самом конце, как я и хотел. Адрес её при этом с не совпадает с тем, что написано в map'е.

 

Собственно, вопросы:

 

- я правильно понимаю, что нашёл баг в линкере?

C:\Program Files\GNU Tools ARM Embedded\4.9 2015q1\bin>arm-none-eabi-ld.exe --version
GNU ld (GNU Tools for ARM Embedded Processors) 2.24.0.20150304

По хорошему, он должен работать единообразно. Или же единообразно не работать :-)

 

- (более насущный) как по-человечески сделать?

 

UPDATE

Вот так работает:

    /* конец данных во флеш - кладём сюда контрольную сумму */
    .CheckSum  (_sidata + SIZEOF(.data)) :
    {
        . = ALIGN(4);
        KEEP(*(.CheckSum))
    } > FLASH

 

Плохо, что я никак концепцию этого странного скрипта не пойму...

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


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

Вы можете написать просто

    /* конец данных во флеш - кладём сюда контрольную сумму */
    .text.CheckSum :
    {
        . = ALIGN(4);
        KEEP(*(.CheckSum))
    } > FLASH

И оно ляжет вслед за всем предыдущим содержанием региона FLASH. Причем во избежание неприятных сюрпризов (типа выкидывания этой секции при генерации .hex) имя этой секции должно начинаться с .text.

 

А еще можно там же определить символ конца занятой памяти (для расчета этой самой контрольной суммы в программе):

    /* конец данных во флеш - кладём сюда контрольную сумму */
    .text.CheckSum :
    {
        . = ALIGN(4);
        KEEP(*(.CheckSum))
        _image_end = .;
    } > FLASH

 

 

И еще - смею предположить, что в объявлении секций .bss и .data у вас тоже прописаны эти совершенно лишние AT(). Положитесь на линкер, он сам умеет размещять секции подряд:

    .data :
    {
        . = ALIGN(4);
        _sdata = .;                /* start of .data label */
        *(.ramfunc)
        *(.ramfunc.*)
        *(.data)
        *(.data.*)
        . = ALIGN(4);
        _edata = .;                /* end of .data label */
    } > RAM AT > FLASH
    _sidata = LOADADDR(.data);    /* start of initialized data label */
    .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

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


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

Сергей, спасибо.

Корректно Ваш пример заработал только после изъятия AT() у секции .data

Без этого линкер пытался наложить .data и .CheckSum и падал с ошибкой.

 

 

 

А скрипт с "совершенно лишними AT()" написал не я.

Вот он, виновник :-)

 

//*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
//*     NICKNAME:  scmRTOS
//*     PROCESSOR: ARM Cortex-M3 
//*     TOOLKIT:   ARM GCC
//*     PURPOSE:   Port Test File
//*     gcc port by Anton B. Gusev aka AHTOXA, Copyright (c) 2009-2012

 

/*************************************************
* linker script for STM32F10x Connectivity Line Devices
************************************************/ 

ENTRY(Reset_Handler)

_Minimum_Stack_Size = 0x100 ;

MEMORY
{
RAM (xrw)	: ORIGIN = 0x20000000, LENGTH =  64K
FLASH (rx)	: ORIGIN = 0x08000000, LENGTH = 256K
}

/* higher address of the user mode stack */
PROVIDE ( _estack = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 8 ,8) );

SECTIONS
{
.isr_vector :
{
	. = ALIGN(4);
	KEEP(*(.isr_vector))
	. = ALIGN(4);
} > FLASH

.text :
{
	__ctors_start__ = .;
	KEEP(SORT(*)(.init_array))  /* eabi uses .init_array for static constructor lists */
	__ctors_end__ = .;

	__dtors_start__ = .;
	__dtors_end__ = .;

	. = ALIGN(4);
	*(.text)                   /* remaining code */
	*(.text.*)
	*(.rodata)                 /* read-only data (constants) */
	*(.rodata*)

	*(.eh_frame_hdr)
	*(.eh_frame)
	*(.ARM.extab* .gnu.linkonce.armextab.*)
	*(.gcc_except_table)
	*(.eh_frame_hdr)
	*(.eh_frame)

	*(.glue_7)
	*(.glue_7t)
	. = ALIGN(4);
} > FLASH

/* .ARM.exidx is sorted, so has to go in its own output section.  */
__exidx_start = .;
.ARM.exidx :
{
	*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;

.text.align :
{
	. = ALIGN(8);
	_etext = .;
	_sidata = _etext;		/* start of initialized data label */
} > FLASH

.data : AT ( _sidata )		/* AT makes the LMA follow on in the binary image */
{
	. = ALIGN(4);
	_sdata = .;				/* start of .data label */
	KEEP( *(.data) )
	KEEP( *(.data.*) )
	. = ALIGN(4);
	_edata = .;				/* end of .data label */
} > RAM

/* .bss section - uninitialized data */
.bss :
{
	. = 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

/*
* 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 = . ;
   } >RAM


PROVIDE( _heap = _ebss );
PROVIDE ( _eheap = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 8 ,8) );

/*
* 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) }
}

 

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


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

А скрипт с "совершенно лишними AT()" написал не я.

Вот он, виновник :-)

У виновника "AT" - это правильный, нужный AT:-)

И тот, который вы убрали - он тоже нужен. Это собственно один и тот же AT, просто указанный разными способами.

        ...
        _sidata = _etext;      /* засекли адрес во флеш (LMA) */
    } > FLASH
    .data : AT ( _sidata )        /* Указываем, что образ секции .data (инициализированные данные) */
    {                        /* лежит во флеше начиная с адреса _sidata.  */
        ...                    /* Потом стартовый код скопирует их в RAM.  */ 
    } > RAM

То же самое можно написать иначе:

    .data :
    {                        /* Образ секции .data будет во флеш сразу за предыдущей секцией */
        ...
    } > RAM AT > FLASH

У вас без этого AT инициализированные переменные должны перестать инициализироваться.

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


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

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

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

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

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

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

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

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

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

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