Reputation: 41
I'm wondering if there's a way to obtain the ROM address used to seed the initial value of a RAM variable? Given a statement static uint32_t foo = 0x12345678;
the initial value 0x12345678
is present as ROM somewhere to serve as the initial value at &foo
. At some point in time I'd like to be able to reset the value of foo
to it's initial state.
I could create a second variable const static uint32_t initial_foo = 0x12345678;
to use but that will then double the ROM data space needed to store variables for this use case.
Can the offset &foo
from the beginning of RAM (or more specifically &_srelocate
, see the linker script below) be reliably correlated with one of the symbols in ROM space?
Selected parts of the ARM/GNU C linker v 6.3.1 script are below.
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00100000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x3000;
__ram_end__ = ORIGIN(ram) + LENGTH(ram) - 4;
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
/* .bss and stack sections removed */
. = ALIGN(4);
_end = . ;
}
Upvotes: 2
Views: 620
Reputation: 213832
Instead of having one RAM variable type foo = value;
, simply make one variable const type foo = value;
and ensure it is allocated in ROM (should be the case if the variable has static storage duration). Then manually copy it to RAM as needed. This way the value is only stored once in ROM; initializers of ROM variables are not stored separately.
Then you won't be wasting any memory and you won't have to worry about somehow searching through .rodata
for the initializer value, which would be rather questionable practice.
Upvotes: 5