How to keep rodata located with the function that created it
I’m trying to make .rodata section location stay with its associated function memory location. I’m using the GNU compiler/linker, bare metal, plain-jane c, with an STM32L4A6 micro-controller.
I have a custom board using an STM32L4A6 controller with 1Meg of Flash divided into 512 - 2K pages. Each page can be individually erased and programmed from a function running in RAM. I’d like to take advantage of this fine-grained flash organization to create an embedded firmware application that can be updated on-the-fly by modifying or adding individual functions in the code. My scheme is to dedicate a separate page of flash for each function that might ever need to be changed or created. It’s extremely wasteful of flash but I’ll never use more than ~10% of it so I can afford to to be wasteful. I’ve made some progress on this and can now make significant changes to the operation of my application by uploading very small bits of binary code. These “Patches” often do not even require a system reboot.
The problem I’m having is that when a function contains any sort of constant data, such as a literal string, it winds up in the .rodata section. I need the rodata for a given function to stay in the same area as the function that created it. Does anyone know how I might be able to force the .rodata that is created in a function to stay attached to that same function in flash? Like maybe the .rodata from that function could be positioned immediately following the function itself? Maybe I need to use -ffunction-sections or something like that? I’ve been through the various linker manuals but still can’t figure how to do this. Below is the start of my linker script. I don’t know how to include function .rodata in the individual page sections.
Example function:
#define P018 __attribute__((long_call, section(".txt018"))) P018 Function18(int A, int B){int C = A*B; return C;}
A better example that shows my problem would be the following:
#define P152 __attribute__((long_call, section(".txt152"))) P152 void TestFunc(int A){printf("%d Squared Is: %d\r\n",A,A*A);}
In this case, the binary equivalent of “%d Squared Is: %d\r\n” can be found in .rodata with all of the other literal strings in my program. I would prefer it to be located in section .txt152 .
Linker Script snippet (Mostly generated from a simple console program.)
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 . . .
In case anyone’s interested, here’s my RAM code for doing the erase/program operation
__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 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;iSR & 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 }