escou64
escou64

Reputation: 66

Linker script RAM intialization in ROM

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

Answers (1)

0___________
0___________

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

Related Questions