Я пытаюсь сделать так, чтобы местоположение раздела .rodata оставалось с соответствующим расположением памяти функций. Я использую компилятор/компоновщик GNU, чистое железо, plain-jane c, с микроконтроллером STM32L4A6.
У меня есть специальная плата, использующая контроллер STM32L4A6 с 1 мегабайтом флэш-памяти, разделенным на 512–2 КБ страниц. Каждую страницу можно индивидуально стереть и запрограммировать с помощью функции, работающей в ОЗУ. Я хотел бы воспользоваться преимуществами этой тонкой организации флэш-памяти для создания встроенного приложения встроенного ПО, которое можно было бы обновлять на лету, изменяя или добавляя отдельные функции в коде. Моя схема состоит в том, чтобы выделить отдельную страницу флэш-памяти для каждой функции, которую, возможно, когда-либо потребуется изменить или создать. Это чрезвычайно расточительно для флэш-памяти, но я никогда не буду использовать более ~ 10%, поэтому я могу позволить себе быть расточительным. Я добился в этом некоторого прогресса и теперь могу внести существенные изменения в работу своего приложения, загрузив очень маленькие фрагменты двоичного кода. Эти «патчи» часто даже не требуют перезагрузки системы.
Проблема, с которой я сталкиваюсь, заключается в том, что когда функция содержит какие-либо постоянные данные, такие как литеральная строка, она оказывается в разделе .rodata. Мне нужно, чтобы родата для данной функции оставалась в той же области, что и функция, которая ее создала. Кто-нибудь знает, как я могу заставить .rodata, созданный в функции, оставаться привязанным к той же функции во флэш-памяти? Например, может быть, .rodata из этой функции можно расположить сразу после самой функции? Может быть, мне нужно использовать -ffunction-sections или что-то в этом роде? Я просмотрел различные руководства по компоновщику, но до сих пор не могу понять, как это сделать. Ниже приведено начало моего скрипта компоновщика. Я не знаю, как включить функцию .rodata в отдельные разделы страницы.
Пример функции:
#define P018 __attribute__((long_call, section(".txt018")))
P018 int Function18(int A, int B){int C = A*B; return C;}
Лучшим примером, показывающим мою проблему, было бы следующее:
#define P152 __attribute__((long_call, section(".txt152")))
P152 void TestFunc(int A){printf("%d Squared Is: %d\r\n",A,A*A);}
В этом случае двоичный эквивалент «%d Squared Is: %d\r\n» можно найти в .rodata вместе со всеми другими литеральными строками в моей программе. Я бы предпочел, чтобы он находился в разделе .txt152.
Фрагмент скрипта компоновщика (в основном генерируется из простой консольной программы.)
MEMORY
{
p000 (rx) : ORIGIN = 0x08000000, LENGTH = 0x8000
p016 (rx) : ORIGIN = 0x08008000, LENGTH = 0x800
p017 (rx) : ORIGIN = 0x08008800, LENGTH = 0x800
p018 (rx) : ORIGIN = 0x08009000, LENGTH = 0x800
.
.
.
p509 (rx) : ORIGIN = 0x080fe800, LENGTH = 0x800
p510 (rx) : ORIGIN = 0x080ff000, LENGTH = 0x800
p511 (rx) : ORIGIN = 0x080ff800, LENGTH = 0x800
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
ram2 (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
.vectors :
{
KEEP(*(.isr_vector .isr_vector.*))
} > p000
.txt016 : { *(.txt016) } > p016 /* first usable 2k page following 32k p000 */
.txt017 : { *(.txt017) } > p017
.txt018 : { *(.txt018) } > p018
.
.
.
.txt509 : { *(.txt509) } > p509
.txt510 : { *(.txt510) } > p510
.txt511 : { *(.txt511) } > p511
.text :
{
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
} > p000
.
.
.
Если кому-то интересно, вот мой код RAM для выполнения операции стирания/программирования
__attribute__((long_call, section(".data")))
void CopyPatch
(
unsigned short Page,
unsigned int NumberOfBytesToFlash,
unsigned char *PatchBuf
)
{
unsigned int i;
unsigned long long int *Flash;
__ASM volatile ("cpsid i" : : : "memory"); //disable interrupts
Flash = (unsigned long long int *)(FLASH_BASE + Page*2048); //set flash memory pointer to Page address
GPIOE->BSRR = GPIO_BSRR_BS_1; //make PE1(LED) high
FLASH->KEYR = 0x45670123; //unlock the flash
FLASH->KEYR = 0xCDEF89AB; //unlock the flash
while(FLASH->SR & FLASH_SR_BSY){} //wait while flash memory operation is in progress
FLASH->CR = FLASH_CR_PER | (Page << 3); //set Page erase bit and the Page to erase
FLASH->CR |= FLASH_CR_STRT; //start erase of Page
while(FLASH->SR & FLASH_SR_BSY){} //wait while Flash memory operation is in progress
FLASH->CR = FLASH_CR_PG; //set flash programming bit
for(i=0;i<(NumberOfBytesToFlash/8+1);i++)
{
Flash[i] = ((unsigned long long int *)PatchBuf)[i]; //copy RAM to FLASH, 8 bytes at a time
while(FLASH->SR & FLASH_SR_BSY){} //wait while flash memory operation is in progress
}
FLASH->CR = FLASH_CR_LOCK; //lock the flash
GPIOE->BSRR = GPIO_BSRR_BR_1; //make PE1(LED) low
__ASM volatile ("cpsie i" : : : "memory"); //enable interrupts
}
.rodata
Я подделал один с помощьюchar *last; int fnc(int a,int b) { int c = a * b; last = "fnc"; return c }
Вместо того, чтобы это делал я, у вас есть функция, которая показывает все интересующие вас пограничные случаи? - person Craig Estey   schedule 17.04.2020