Директива GCC (NOLOAD) в любом случае загружает память в раздел

Эта "проблема" является результатом решения. Вот что происходит. У меня есть несколько разделов в оперативной памяти, определенных для определенных вещей. Один из разделов (.flashroutines) в оперативной памяти - это место, где находятся процедуры стирания флэш-памяти и программирования. Этот раздел определяется в файле.ld следующим образом.

.flashroutines 0x20000100 (NOLOAD) :
{
. = ALIGN(4);
*(.flashroutines* .gnu.linkonce.flashroutines.*)
KEEP(*(.flashroutines))
} > RAM 

(NOLOAD) Директива была помещена в этот раздел в качестве эксперимента (это помогло решить проблему большого файла.bin). Перед NOLOAD был размещен в этом разделе, двоичный файл был ОГРОМНЫМ. И файл программы не будет загружаться, потому что загрузчик сказал, что файл содержит флэш-адреса, которые были вне диапазона. Насколько я мог судить, шестнадцатеричный файл был в порядке. После NOLOAD был размещен в этом разделе, все выглядело хорошо. Программа загрузится, и файл карты выглядел нормально. Но здесь есть подвох. Я ожидал, что в раздел.flashroutines не будет загружен код. Но после перехода к процедуре программирования флэш-памяти я обнаружил, что процедуры программирования флэш-памяти существуют. Поскольку эти подпрограммы находятся в ОЗУ, единственный способ получить их - загрузить их во время выполнения.

Теперь о вопросах.

  1. Как код попал в ОЗУ с NOLOAD директива для этого раздела?
  2. Почему файл.bin был таким большим без него?

Изменить 1:

Удалить код разборки. Он не был загружен в оперативную память. См. Правка 3. Правка 2 все еще применяется.

Изменить 2.

Вот что я обнаружил об очень большом.bin-файле. Похоже, что компоновщик создал файл bin, начиная с адреса 0x00000000 (ARM - Flash), как и должно быть. Однако создается впечатление, что он обрабатывает раздел.flashroutines, начинающийся с адреса 0x20000100, как если бы он находился в разделе.text, или флэш-память. В результате этого компоновщик заполняет все неиспользуемые адреса между фактическим концом кода во флэш-памяти (где-то около 0x0000 1FFF), вплоть до 0x2000 0000 в ОЗУ с 0x00. Если я добавлю директиву (NOLOAD) в ЭТОТ РАЗДЕЛ, то компоновщик не будет выполнять их заполнение. Вероятно, есть проблема с моим файлом сценария компоновщика.

Раздел.flashroutines вырезан из области RAM, как показано ниже.

MEMORY
{
FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x20000 /* 128k */
/*  CRC (rx) : ORIGIN = 0x2800, LENGTH = 4   */ 
/*  RAM_CODE (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000     32k executable 
code area in RAM */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 /* 32k */
}

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

Редактировать № 3.

Оказывается, что код, который должен был быть загружен в ОЗУ в разделе.flashroutines, фактически не был загружен. Данные, которые были в этих местах ОЗУ, были перенесены из другого времени. Я очистил эти места в самом начале кода запуска, и этот раздел в ОЗУ никогда не загружался до перехода на главную. В подпрограмме запуска есть код, который используется для инициализации различных "предопределенных" разделов. Но код для.flashroutines не копируется с флэш-памяти в RAM. На самом деле, я даже не знаю, куда во флеше искать флеш-копию (оригинал) двух функций.

Вот код запуска, который должен копироваться с флэш-памяти в оперативную память во время выполнения.

#define __STARTUP_COPY_MULTIPLE  1

#ifdef __STARTUP_COPY_MULTIPLE
/*  Multiple sections scheme.
*
*  Between symbol address __copy_table_start__ and __copy_table_end__,
*  there are array of triplets, each of which specify:
*    offset 0: LMA of start of a section to copy from
*    offset 4: VMA of start of a section to copy to
*    offset 8: size of the section to copy. Must be multiply of 4
*
*  All addresses must be aligned to 4 bytes boundary.
*/
pTable = &__copy_table_start__;

for (; pTable < &__copy_table_end__; pTable = pTable + 3)
{
    pSrc  = (uint32_t*)*(pTable + 0);
    pDest = (uint32_t*)*(pTable + 1);
    for (; pDest < (uint32_t*)(*(pTable + 1) + *(pTable + 2)) ; )
    {
        *pDest++ = *pSrc++;
    }
}
#else

/*  Single section scheme.
*
*  The ranges of copy from/to are specified by following symbols
*    __etext: LMA of start of the section to copy from. Usually end of text
*    __data_start__: VMA of start of the section to copy to
*    __data_end__: VMA of end of the section to copy to
*
*  All addresses must be aligned to 4 bytes boundary.
*/

pSrc  = &__etext;
pDest = &__data_start__;

for ( ; pDest < &__data_end__ ; )
{
    *pDest++ = *pSrc++;
}
#endif    /*__STARTUP_COPY_MULTIPLE */

Вот часть файла сценария компоновщика, который связан с разделом "Несколько копий" выше.

/**************************************************** 
To copy multiple ROM to RAM sections,
uncomment .copy.table section and,
define __STARTUP_COPY_MULTIPLE in startup
****************************************************/

.copy.table :
{
    . = ALIGN(4);
    __copy_table_start__ = .;
    LONG (__etext)
    LONG (__data_start__)
    LONG (__data_end__ - __data_start__)
    /*    LONG (__etext2)                           */
    /*    LONG (__data2_start__)                    */
    /*    LONG (__data2_end__ - __data2_start__)    */

    /* DON'T I NEED SOMETHING HERE TO COPY .flashroutines ??? */

    __copy_table_end__ = .;
} > FLASH

Вот фрагмент кода в заголовочном файле для функции proto.

void FlashErasePage(unsigned long);
void FlashWriteData(unsigned long, unsigned long, unsigned long);

Вот код.c.

__attribute__( ( long_call, section(".flashroutines") ) ) void FlashWriteData (unsigned long flash_address, unsigned long data_size, unsigned long flash_data)
{
code body
}

__attribute__( ( long_call, section(".flashroutines") ) ) void FlashErasePage (unsigned long pagenum)  
{
code body
}

Теперь еще несколько комментариев и вопрос или два. Если я скажу что-нибудь не так, пожалуйста, поправьте меня.

  1. Похоже, что компилятор будет генерировать независимый от позиции код при компиляции функций FlashWriteData и FlashErasePage.
  2. Когда компоновщик запускается, он должен видеть, что эти функции должны идти в раздел.flashroutines по адресу, определенному в файле скрипта.
  3. Затем компоновщик создаст позиционно-зависимый код (код, который будет запускаться из ОЗУ, но компоновщик должен где-то поместить этот код во флэш-память.
  4. При запуске некоторые разделы из флэш-памяти могут быть скопированы в оперативную память. Раздел.data является одним из них для инициализированных переменных ОЗУ, которых у меня нет. Другой раздел, который нужно будет скопировать, это раздел.flashroutines, где функции FlashWriteData и FlashErasePage теперь будут находиться в оперативной памяти.

Вопросы.

Нужно ли что-то добавить в файл сценария компоновщика в .copy.table раздел для создания записи таблицы для файла запуска для использования во время копирования раздела?

Как я могу узнать, где компилятор / компоновщик поместил оригинальную копию флеш-подпрограмм во флеш-память?

Поскольку подпрограммы копирования памяти при запуске очень просты, не должна ли эта копия подпрограмм во флэш-памяти быть точной копией того, что будет помещено в ОЗУ?

Мне жаль, что это продолжается и продолжается, но я чувствую себя слепым с фонариком. Все, кого я встречаю, говорят мне, что он включен, но я все еще ничего не вижу.

0 ответов

Другие вопросы по тегам