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

Перемещение кода в память, как указать где копия кода должна быть размещена во флеше.

Есть связка: важный кусок программы(ВКП)+остальное. Среди прочего ВКП нужно скопировать в память и выполняться оттуда. Причем нужно что бы в случае если "остальное" будет стерто из флеша, то ВКП смог бы продолжать работать даже после ресета. Да, похоже на связку бут+программа, но связей между 2 кусками больше причем в обе стороны и они НЕ должны обновляться независимо. Соответственно что бы не городить разделение логически одной программы на 2 куска хочется указать линкеру что бы он часть ВКП отмапленную в память хранил в части флеша относящейся к ВКП же.

 

Т.е. структура флеша:

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

структура памяти:

код и переменные ВКП, память для остальной части программы

 

Как бы это сделать через ld? Пробовал через разные секции для разных частей кода, однако сохраненное для загрузки в память всё равно линкуется в конец бинарника. Как это сделать правильно?

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


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

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. Если вы стёрли флэш и сделали ресет, то передача управления идёт в соответствие с режимом загрузки. Если ваш МК позволяет стартовать из ОЗУ после ресета, то всё должно проканать... Не знаю, надо думать!

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


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

Причем нужно что бы в случае если "остальное" будет стерто из флеша, то ВКП смог бы продолжать работать даже после ресета.

Вне зависимости от того, как этот ВКП будет размещён в ОЗУ, нужно гарантировать, что все функции, которые вызывает этот ВКП, тоже сидели в ОЗУ. GCC неявно вызывает функции для многих дел: арифметика, копирование памяти и т.п.

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


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

Вне зависимости от того, как этот ВКП будет размещён в ОЗУ, нужно гарантировать, что все функции, которые вызывает этот ВКП, тоже сидели в ОЗУ. GCC неявно вызывает функции для многих дел: арифметика, копирование памяти и т.п.

 

Почему ?

 

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


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

1. Всё, что должно помещаться в ram, есть initialized data - секция .data по умолчанию. Ну и ссылки начала и конца - _sidata, _edata.

По сути то, что вы описали - есть ramfunc. Если абстрагироваться от заморочек с ресетом по питанию и передачей управления, то кусок скрипта линкёра примерно такой должен быть

Странно, примерно такой же вариант пробовал и линковалось всё равно в конец. Попробую подредактировать под свои нужды Ваш.

Вне зависимости от того, как этот ВКП будет размещён в ОЗУ, нужно гарантировать, что все функции, которые вызывает этот ВКП, тоже сидели в ОЗУ. GCC неявно вызывает функции для многих дел: арифметика, копирование памяти и т.п.

Это понятная грабля, спасибо за напоминание.

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


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

Сделал как предложил Aaron, но всё равно во флеше загружаемое в память отправляется в конец, а не как должно было бы быть если заполнять флеш по порядку как в скрипте. Т.е флеш вместо того что в 1 сообщении получается:

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

ЧЯДНТ?

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


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

Было бы предпочтительней понять как перемещать сразу объектные файлы, без редактирования исходников. Пробую так:

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 <адрес в конце слинкованого флеша>

Изменено пользователем Kabdim

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


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

Посмотрел у себя - то же самое. Похоже, то, что кладётся в секцию через AT>, попадает туда в последнюю очередь. Хм...

Попробуйте тогда вот так:

    .text : ALIGN(4)
    {
        __vectors_start__ = ABSOLUTE(.);
        KEEP(*(.isr_vector))
        _label1 = .
    } >FLASH

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

Я думал, что это одно и то же, но теперь вижу, что этот вариант даёт больше контроля.

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


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

Размещение в памяти теперь правильное, но конфликтует с остальным содержимым, последний линкуется во флеш в то же место:

section .data loaded at [00000300,00000327] overlaps section .text loaded at [00000000,0000480f]

Видимо надо сделать вторую секцию для кода и размещать её так же принудительно.

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


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

Прошу помочь с этим сдвигом. Мозги кипят. Пробую:

    .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.

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


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

Подождите, что значит, не работает } > RAM AT > FLASH ???

Может, у вас всё же что-то не так в скриптах?

 

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

 

Ставлю секцию 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;

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


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

Подождите, что значит, не работает } > RAM AT > FLASH ???

Может, у вас всё же что-то не так в скриптах?

В вашем же примере у вас после отмапленных в память секций нет секций с кодом во флеше. Если её добавить, то размещение секций смапленных в память во флеше сдвинется, если указывать "> RAM AT > FLASH". А рецепт Антохи и позволяет произвольно тасовать секции во флеше и загрузочные куски секций, который будут скопированы в память. Аля: прерывания - код для копирования во флеш - код который остается во флеше. Тасовать секции который находятся только во флеше или только в памяти между собой порядком объявления - нет проблем. А вот всё вместе и было задачей.

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

Вы меня зря хвалите, он отредактирован после генератора, а не ручками написан.

Изменено пользователем Kabdim

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


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

Какие-то сложные у вас решения

    .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

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


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

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

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

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

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

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

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

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

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

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