Reputation: 66
I am currently writing my own linker script to execute a baremetal RISC-V program. I want to place in ROM (exactly at the address _idata if it is possible) initial values of global variables which are in RAM (at boot time, a program will be responsible to copy the different values from the ROM to the RAM). To do this, I use the VMA/LMA mechanism.
Here is my linker script:
MEMORY
{
ROM (rx) : ORIGIN = 0x00004000, LENGTH = 0x00004000
RAM (rwx) : ORIGIN = 0x00008000, LENGTH = 0x00004000
}
STACK_SIZE = 0x3000;
BOOT_PC = 0x1000;
/* Section Definitions */
SECTIONS
{
/* Code and constants */
.text :
{
_stext = . ;
*(.rodata*);
*(.srodata*);
*(.text*);
_etext = . ;
. = ALIGN(8);
/* Initial data of RAM */
_idata = . ;
} > ROM
/* Initialized data */
/* Relocate in ROM */
.data : AT (_idata)
{
. = ALIGN(8);
_sdata = . ;
*(.sdata .sdata.* .sdata2.*)
*(.data .data.*)
_edata = . ;
. = ALIGN(8);
} > RAM
/* Unitialized data */
.bss (NOLOAD) :
{
. = ALIGN(8);
_sbss = . ;
*(.bss*);
*(.sbss*);
*(COMMON);
_ebss = . ;
. = ALIGN(8);
} > RAM
/* Stack */
.stack (NOLOAD):
{
. = ALIGN(8);
. = . + STACK_SIZE;
. = ALIGN(8);
_stack = . ;
} > RAM
}
And here is my basic C program test:
int d1 = 0x42;
const int d2 = 0x40;
int d3 = 0x35;
int main () {
return 0;
}
However, surprisingly for me, the initial values are still placed in the RAM (except the d2 constant):
00004000 <d2>:
4000: 0040 .2byte 0x40
...
00004004 <main>:
4004: 00000513 li x10,0
4008: 00008067 ret
0000400c <_etext>:
400c: 0000 .2byte 0x0
...
Disassembly of section .data:
00008000 <d3>:
8000: 0035 .2byte 0x35
...
00008004 <d1>:
8004: 0042 .2byte 0x42
...
Could someone explain to me what I am doing wrong? I read the following information, I have also tested the syntax > RAM AT > ROM but still without success ...
Upvotes: 0
Views: 1002
Reputation: 67546
You need to copy it as startup.
_sidata = LOADADDR(.data);
/* ... */
.data :
{
. = ALIGN(8);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> ROM
The best is to have a separate startup C code, but as a workaround you can use gcc constructor
extern uint8_t _sdata[];
extern uint8_t _edata[];
extern uint8_t _sidata[];
static void __attribute__((constructor)) copyRAMfunctions(void)
{
memcpy(_sdata, _sidata, _edata - sdata);
}
Upvotes: 2