Директива GCC (NOLOAD) в любом случае загружает память в раздел
Эта "проблема" является результатом решения. Вот что происходит. У меня есть несколько разделов в оперативной памяти, определенных для определенных вещей. Один из разделов (.flashroutines) в оперативной памяти - это место, где находятся процедуры стирания флэш-памяти и программирования. Этот раздел определяется в файле.ld следующим образом.
.flashroutines 0x20000100 (NOLOAD) :
{
. = ALIGN(4);
*(.flashroutines* .gnu.linkonce.flashroutines.*)
KEEP(*(.flashroutines))
} > RAM
(NOLOAD)
Директива была помещена в этот раздел в качестве эксперимента (это помогло решить проблему большого файла.bin). Перед NOLOAD
был размещен в этом разделе, двоичный файл был ОГРОМНЫМ. И файл программы не будет загружаться, потому что загрузчик сказал, что файл содержит флэш-адреса, которые были вне диапазона. Насколько я мог судить, шестнадцатеричный файл был в порядке. После NOLOAD
был размещен в этом разделе, все выглядело хорошо. Программа загрузится, и файл карты выглядел нормально. Но здесь есть подвох. Я ожидал, что в раздел.flashroutines не будет загружен код. Но после перехода к процедуре программирования флэш-памяти я обнаружил, что процедуры программирования флэш-памяти существуют. Поскольку эти подпрограммы находятся в ОЗУ, единственный способ получить их - загрузить их во время выполнения.
Теперь о вопросах.
- Как код попал в ОЗУ с
NOLOAD
директива для этого раздела? - Почему файл.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
}
Теперь еще несколько комментариев и вопрос или два. Если я скажу что-нибудь не так, пожалуйста, поправьте меня.
- Похоже, что компилятор будет генерировать независимый от позиции код при компиляции функций FlashWriteData и FlashErasePage.
- Когда компоновщик запускается, он должен видеть, что эти функции должны идти в раздел.flashroutines по адресу, определенному в файле скрипта.
- Затем компоновщик создаст позиционно-зависимый код (код, который будет запускаться из ОЗУ, но компоновщик должен где-то поместить этот код во флэш-память.
- При запуске некоторые разделы из флэш-памяти могут быть скопированы в оперативную память. Раздел.data является одним из них для инициализированных переменных ОЗУ, которых у меня нет. Другой раздел, который нужно будет скопировать, это раздел.flashroutines, где функции FlashWriteData и FlashErasePage теперь будут находиться в оперативной памяти.
Вопросы.
Нужно ли что-то добавить в файл сценария компоновщика в .copy.table
раздел для создания записи таблицы для файла запуска для использования во время копирования раздела?
Как я могу узнать, где компилятор / компоновщик поместил оригинальную копию флеш-подпрограмм во флеш-память?
Поскольку подпрограммы копирования памяти при запуске очень просты, не должна ли эта копия подпрограмм во флэш-памяти быть точной копией того, что будет помещено в ОЗУ?
Мне жаль, что это продолжается и продолжается, но я чувствую себя слепым с фонариком. Все, кого я встречаю, говорят мне, что он включен, но я все еще ничего не вижу.