Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Перемещение кода в память, как указать где копия кода должна быть размещена во флеше.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Kabdim
Есть связка: важный кусок программы(ВКП)+остальное. Среди прочего ВКП нужно скопировать в память и выполняться оттуда. Причем нужно что бы в случае если "остальное" будет стерто из флеша, то ВКП смог бы продолжать работать даже после ресета. Да, похоже на связку бут+программа, но связей между 2 кусками больше причем в обе стороны и они НЕ должны обновляться независимо. Соответственно что бы не городить разделение логически одной программы на 2 куска хочется указать линкеру что бы он часть ВКП отмапленную в память хранил в части флеша относящейся к ВКП же.

Т.е. структура флеша:
прерывания, startup&main, код и переменные ВКП который нужно загрузить в память, остальное
структура памяти:
код и переменные ВКП, память для остальной части программы

Как бы это сделать через ld? Пробовал через разные секции для разных частей кода, однако сохраненное для загрузки в память всё равно линкуется в конец бинарника. Как это сделать правильно?
Aaron
1. Всё, что должно помещаться в ram, есть initialized data - секция .data по умолчанию. Ну и ссылки начала и конца - _sidata, _edata.
По сути то, что вы описали - есть ramfunc. Если абстрагироваться от заморочек с ресетом по питанию и передачей управления, то кусок скрипта линкёра примерно такой должен быть:
Код
    .text.align :
    {
        . = ALIGN(8);
        _etext = .;
        _sidata = _etext;        /* start of initialized data label */
    } > FLASH

    /* .ramfunc : AT ( _sidata ) */    /* RAM functions section */
    /* RAM functions section */
    .ramfunc :                    
    {
        . = ALIGN(8);
        __exec_mem_start__ = .;
        _sdata = .;                /* start of .data label */
        SORT(*)(.ramfunc)
        SORT(*)(.ramfunc.*)
        SORT(*)(EXECUTABLE_MEMORY_SECTION*)    /* eeprom functions from MDR_StdPeriph_Driver */
        . = ALIGN(4);
        __exec_mem_end__ = .;
    } > RAM AT > FLASH

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


Играясь с указателем адреса .ramfunc : AT ( _sidata ), можно расположить где захотите. В моём примере будет как раз то, что вы просите.

2. Если вы стёрли флэш и сделали ресет, то передача управления идёт в соответствие с режимом загрузки. Если ваш МК позволяет стартовать из ОЗУ после ресета, то всё должно проканать... Не знаю, надо думать!
scifi
Цитата(Kabdim @ Feb 15 2016, 13:13) *
Причем нужно что бы в случае если "остальное" будет стерто из флеша, то ВКП смог бы продолжать работать даже после ресета.

Вне зависимости от того, как этот ВКП будет размещён в ОЗУ, нужно гарантировать, что все функции, которые вызывает этот ВКП, тоже сидели в ОЗУ. GCC неявно вызывает функции для многих дел: арифметика, копирование памяти и т.п.
dimka76
Цитата(scifi @ Feb 15 2016, 16:01) *
Вне зависимости от того, как этот ВКП будет размещён в ОЗУ, нужно гарантировать, что все функции, которые вызывает этот ВКП, тоже сидели в ОЗУ. GCC неявно вызывает функции для многих дел: арифметика, копирование памяти и т.п.


Почему ?
Kabdim
Цитата(Aaron @ Feb 15 2016, 15:46) *
1. Всё, что должно помещаться в ram, есть initialized data - секция .data по умолчанию. Ну и ссылки начала и конца - _sidata, _edata.
По сути то, что вы описали - есть ramfunc. Если абстрагироваться от заморочек с ресетом по питанию и передачей управления, то кусок скрипта линкёра примерно такой должен быть

Странно, примерно такой же вариант пробовал и линковалось всё равно в конец. Попробую подредактировать под свои нужды Ваш.
Цитата(scifi @ Feb 15 2016, 16:01) *
Вне зависимости от того, как этот ВКП будет размещён в ОЗУ, нужно гарантировать, что все функции, которые вызывает этот ВКП, тоже сидели в ОЗУ. GCC неявно вызывает функции для многих дел: арифметика, копирование памяти и т.п.

Это понятная грабля, спасибо за напоминание.
Kabdim
Сделал как предложил Aaron, но всё равно во флеше загружаемое в память отправляется в конец, а не как должно было бы быть если заполнять флеш по порядку как в скрипте. Т.е флеш вместо того что в 1 сообщении получается:
прерывания, startup&main, остальное, код и переменные ВКП который нужно загрузить в память
ЧЯДНТ?
AHTOXA
Покажите скрипт линкера.
Kabdim
Было бы предпочтительней понять как перемещать сразу объектные файлы, без редактирования исходников. Пробую так:
CODE

INCLUDE "corp_AES_TEST_Debug_library.ld"
INCLUDE "corp_AES_TEST_Debug_memory.ld"

ENTRY(ResetISR)

SECTIONS
{
/* MAIN TEXT SECTION */
.text : ALIGN(4)
{
FILL(0xff)
__vectors_start__ = ABSOLUTE(.) ;
KEEP(*(.isr_vector))
/* Global Section Table */
. = ALIGN(4) ;
__section_table_start = .;
__data_section_table = .;
LONG(LOADADDR(.data));
LONG( ADDR(.data));
LONG( SIZEOF(.data));
LONG(LOADADDR(.data_RAM2));
LONG( ADDR(.data_RAM2));
LONG( SIZEOF(.data_RAM2));
__data_section_table_end = .;
__bss_section_table = .;
LONG( ADDR(.bss));
LONG( SIZEOF(.bss));
LONG( ADDR(.bss_RAM2));
LONG( SIZEOF(.bss_RAM2));
__bss_section_table_end = .;
__section_table_end = . ;
/* End of Global Section Table */

*(.after_vectors*)

/* Code Read Protect data */
. = 0x000002FC ;
PROVIDE(__CRP_WORD_START__ = .) ;
KEEP(*(.crp))
PROVIDE(__CRP_WORD_END__ = .) ;
ASSERT(!(__CRP_WORD_START__ == __CRP_WORD_END__), "Linker CRP Enabled, but no CRP_WORD provided within application");
/* End of Code Read Protect */
} >MFlash128

/* Main DATA section (RamLoc8) */
.data : ALIGN(4)
{
FILL(0xff)
_data = . ;
*(vtable)
*(.ramfunc*)
*wdt.o(.text*)
*wdt.o(.rodata .rodata.* .constdata .constdata.*)
*eeprom.o(.text*)
*eeprom.o(.rodata .rodata.* .constdata .constdata.*)
. = ALIGN(4);
*(.data*) . = ALIGN(4) ;
_edata = . ;
} > RamLoc8 AT>MFlash128

.text : ALIGN(4)
{
*(EXCLUDE_FILE(*wdt.o *eeprom.o) .text*)*(EXCLUDE_FILE(*wdt.o *eeprom.o) .rodata .rodata.* .constdata .constdata.*)
. = ALIGN(4);
} > MFlash128
/*
* for exception handling/unwind - some Newlib functions (in common
* with C++ and STDC++) use this.
*/
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > MFlash128
__exidx_start = .;

.ARM.exidx : ALIGN(4)
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > MFlash128
__exidx_end = .;

_etext = .;

/* DATA section for RamUsb2 */
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
PROVIDE(__start_data_RAM2 = .) ;
*(.ramfunc.$RAM2)
*(.ramfunc.$RamUsb2)
*(.data.$RAM2*)
*(.data.$RamUsb2*)
. = ALIGN(4) ;
PROVIDE(__end_data_RAM2 = .) ;
} > RamUsb2 AT>MFlash128

/* MAIN DATA SECTION */
.uninit_RESERVED : ALIGN(4)
{
KEEP(*(.bss.$RESERVED*))
. = ALIGN(4) ;
_end_uninit_RESERVED = .;
} > RamLoc8
/* BSS section for RamUsb2 */
.bss_RAM2 : ALIGN(4)
{
PROVIDE(__start_bss_RAM2 = .) ;
*(.bss.$RAM2*)
*(.bss.$RamUsb2*)
. = ALIGN (. != 0 ? 4 : 1) ; /* avoid empty segment */
PROVIDE(__end_bss_RAM2 = .) ;
} > RamUsb2
/* MAIN BSS SECTION */
.bss : ALIGN(4)
{
_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4) ;
_ebss = .;
PROVIDE(end = .);
} > RamLoc8
/* NOINIT section for RamUsb2 */
.noinit_RAM2 (NOLOAD) : ALIGN(4)
{
*(.noinit.$RAM2*)
*(.noinit.$RamUsb2*)
. = ALIGN(4) ;
} > RamUsb2
/* DEFAULT NOINIT SECTION */
.noinit (NOLOAD): ALIGN(4)
{
_noinit = .;
*(.noinit*)
. = ALIGN(4) ;
_end_noinit = .;
} > RamLoc8

PROVIDE(_pvHeapStart = DEFINED(__user_heap_base) ? __user_heap_base : .);
PROVIDE(_vStackTop = DEFINED(__user_stack_top) ? __user_stack_top : __top_RamLoc8 - 0);

/* ## Create checksum value (used in startup) ## */
PROVIDE(__valid_user_code_checksum = 0 -
(_vStackTop
+ (ResetISR + 1)
+ (( DEFINED(NMI_Handler) ? NMI_Handler : M0_NMI_Handler ) + 1)
+ (( DEFINED(HardFault_Handler) ? HardFault_Handler : M0_HardFault_Handler ) + 1)
)
);
}


В мапе в итоге получаю:
.data 0x10000000 0x28 load address <адрес в конце слинкованого флеша>
AHTOXA
Посмотрел у себя - то же самое. Похоже, то, что кладётся в секцию через AT>, попадает туда в последнюю очередь. Хм...
Попробуйте тогда вот так:
Код
    .text : ALIGN(4)
    {
        __vectors_start__ = ABSOLUTE(.);
        KEEP(*(.isr_vector))
        _label1 = .
    } >FLASH

    .data : AT ( _label1 )
    {  
        . = ALIGN(4);
        *(.ramfunc*)
        *(.data)
        *(.data.*)
    } >RAM

Я думал, что это одно и то же, но теперь вижу, что этот вариант даёт больше контроля.
Kabdim
Размещение в памяти теперь правильное, но конфликтует с остальным содержимым, последний линкуется во флеш в то же место:
section .data loaded at [00000300,00000327] overlaps section .text loaded at [00000000,0000480f]
Видимо надо сделать вторую секцию для кода и размещать её так же принудительно.
Kabdim
Прошу помочь с этим сдвигом. Мозги кипят. Пробую:
Код
    .data :  AT ( _label1 )
    ...
    } > RamLoc8

    . += SIZEOF(.data);
    /* . = _label1  + SIZEOF(.data); */
    
    .text2 : ALIGN(4)    
    {
    ...

Не хочет он сдвигать начало секции. А если поставить внутри секции то будет просто зарезервированный кусок, который всё равно будет конфликтовать.
Kabdim
Тихо сам с собой. Похоже получилось сдвинуть секцию, но как-то через 5 точку. Код примерно такой:
Код
    
/* в конце первой секции с кодом */
           _label2 = ABSOLUTE(.);
     }

     .data :  AT ( _label1 )
       _data = .;
    ...
       _edata = .;
       _new_flash_addr = _label2 + _edata - _data - 0x10000000;
    } > RamLoc8

    /* Если перенести код сюда, то прибавится  лишних 0x20000000 */
    
    .text2 _new_flash_addr  : ALIGN(4)    
    {
    ...


Как избавится от дополнительного смещения на размер смещенения секции памяти пока не могу догадаться. Но такое решение уже работает, но подозреваю что что-то очень важное в логике gnu ld от меня ускользнуло.

Ну и добивая тему:
Цитата
_new_flash_addr = ABSOLUTE(_label2 + _edata - _data);

Наверное надо отшлифовать использованием SIZEOF.
Aaron
Подождите, что значит, не работает } > RAM AT > FLASH ???
Может, у вас всё же что-то не так в скриптах?

К слову, навороченный у вас скрипт! Его ещё покурить надо, да на заметку себе взять, пригодится! wink.gif

Ставлю секцию ramfunc вперёд, выхлоп в map-файле:
Цитата
4 .ramfunc 00000538 20000000 08019a68 00020000 2**3
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 .data 00000890 20000538 08019fa0 00020538 2**3
CONTENTS, ALLOC, LOAD, DATA
6 .bss 00005d54 20000dc8 0801a830 00020dc8 2**3
ALLOC


Ставлю в центр, выхлоп:
Цитата
4 .data 00000890 20000000 08019a68 00020000 2**3
CONTENTS, ALLOC, LOAD, DATA
5 .ramfunc 00000538 20000890 0801a2f8 00020890 2**3
CONTENTS, ALLOC, LOAD, READONLY, CODE
6 .bss 00005d54 20000dc8 0801a830 00020dc8 2**3
ALLOC


Хочу, ставлю даже после bss, выхлоп:
Цитата
4 .data 00000890 20000000 08019a68 00020000 2**3
CONTENTS, ALLOC, LOAD, DATA
5 .bss 00005d54 20000890 0801a2f8 00020890 2**3
ALLOC
6 .ramfunc 00000538 200065e8 0801a2f8 000265e8 2**3
CONTENTS, ALLOC, LOAD, READONLY, CODE


Далее, по поводу объектников - указываете прямо их имена в линкер-скрипте:

Цитата
.my_objects:
{
. = WDT_NEED_ADDR
path1/wdt.o
. = EEPROM_NEED_ADDR
path2/eeprom.o
} > FLASH


Что вам мешает перемещать эти объектники целиком, используя те же указатели . = WDT_NEED_ADDR?

Более того, для отладки можете смотреть из c-кода своего (ну или просто в map-файле) глобальные переменные вида:
Цитата
void * _binary_path1_wdt_c_start, _binary_path1_wdt_c_end;
void * _binary_path2_eeprom_c_start, _binary_path2_eeprom_c_end;
Kabdim
Цитата(Aaron @ Feb 26 2016, 17:07) *
Подождите, что значит, не работает } > RAM AT > FLASH ???
Может, у вас всё же что-то не так в скриптах?

В вашем же примере у вас после отмапленных в память секций нет секций с кодом во флеше. Если её добавить, то размещение секций смапленных в память во флеше сдвинется, если указывать "> RAM AT > FLASH". А рецепт Антохи и позволяет произвольно тасовать секции во флеше и загрузочные куски секций, который будут скопированы в память. Аля: прерывания - код для копирования во флеш - код который остается во флеше. Тасовать секции который находятся только во флеше или только в памяти между собой порядком объявления - нет проблем. А вот всё вместе и было задачей.
Цитата(Aaron @ Feb 26 2016, 17:07) *
К слову, навороченный у вас скрипт! Его ещё покурить надо, да на заметку себе взять, пригодится! wink.gif

Вы меня зря хвалите, он отредактирован после генератора, а не ручками написан.
Сергей Борщ
Какие-то сложные у вас решения
Код
    .text :
    {
        _image_start = .;
        KEEP(*(.isr_vector))
        LONG((_image_end - _image_start) / 4);    /* application size, in 4-byte words */
    } > TEXT
    .data :
    {
        . = ALIGN(4);
        _sdata = .;                /* start of .data label */
        *(.ramfunc)
        *(.ramfunc.*)
        *(.data)
        *(.data.*)
        . = ALIGN(4);
        _edata = .;                /* end of .data label */
    } > RAM AT > TEXT
    _sidata = LOADADDR(.data);    /* start of initialized data label */
    
    .text.1 :
    {
        . = ALIGN(8);
        __ctors_start__ = .;
        KEEP(*(.init_array))  /* eabi uses .init_array for static constructor lists */
               ....
    } > TEXT


Код
.text           0x08001000      0x124
                0x08001000                _image_start = .
*(.isr_vector)
.isr_vector    0x08001000      0x120 ./release/obj/startup.o
                0x08001000                g_pfnVectors
                0x08001120        0x4 LONG 0x1b79 ((_image_end - _image_start) / 0x4)

.vfp11_veneer   0x08001124        0x0
.vfp11_veneer  0x00000000        0x0 linker stubs

.v4_bx          0x08001124        0x0
.v4_bx         0x00000000        0x0 linker stubs

.iplt           0x08001124        0x0
.iplt          0x00000000        0x0 ./release/obj/startup.o

.rel.dyn        0x08001124        0x0
.rel.iplt      0x00000000        0x0 ./release/obj/startup.o

.data           0x20000000        0x4 load address 0x08001124
                0x20000000                . = ALIGN (0x4)
                0x20000000                _sdata = .
*(.ramfunc)
*(.ramfunc.*)
*(.data)
*(.data.*)
.data.__ctype_ptr__
                0x20000000        0x4 /home/serzh/opt/arm-gcc/launchpad/20150306/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m/libc.a(lib_a-ctype_.o)
                0x20000000                __ctype_ptr__
                0x20000004                . = ALIGN (0x4)
                0x20000004                _edata = .
                0x08001124                _sidata = LOADADDR (.data)

.igot.plt       0x20000004        0x0 load address 0x08001128
.igot.plt      0x00000000        0x0 ./release/obj/startup.o

.text.1         0x08001128     0x6cb4
                0x08001128                . = ALIGN (0x8)
                0x08001128                __ctors_start__ = .
*(.init_array)
.init_array    0x08001128        0x4 ./release/obj/adc.o
Kabdim
Сегодня наконец проверил. Досадно. Столько времени потрачено на битье головой об стену. Спасибо, Сергей!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2018 Invision Power Services, Inc.