Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: GCC, размещение переменной по фиксированному адресу
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
esaulenka
Захотелось мне разместить переменную в самом конце используемой области флеш - после секций .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
Petka
Лучше тему перенести в раздел "opensource".
esaulenka
Сергей, спасибо.
Корректно Ваш пример заработал только после изъятия 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


CODE

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

AHTOXA
Цитата(esaulenka @ May 21 2015, 16:18) *
А скрипт с "совершенно лишними AT()" написал не я.
Вот он, виновник :-)

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

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

У вас без этого AT инициализированные переменные должны перестать инициализироваться.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.