In this lesson, you will learn how to configure your linker to ensure that global and static variables containing initial values are correctly copied from non-volatile storage (Flash) to volatile memory (RAM) before your main() function begins.
The Problem: Two Locations, One Variable
When you define a global variable with an initial value, such as int status_code = 10;, the compiler places it in a special section of your object file, typically called .data.
Because your microcontroller’s RAM is volatile, it loses its state when power is cycled. However, the initial value 10 must persist even when the power is off. Therefore, the linker must store that value in your non-volatile Flash memory. At power-up, your system must move that value from Flash to the RAM address where status_code actually resides.
Configuring the Linker Script
To facilitate this, you must define both the load address (where it lives in Flash) and the virtual address (where it lives in RAM) in your linker script. Using the MEMORY commands and sections mapping we discussed previously, your linker script should look like this:
.data :
{
_sdata = .; /* Start address in RAM */
*(.data) /* Include all .data sections from objects */
_edata = .; /* End address in RAM */
} > RAM AT > FLASH /* VMA in RAM, LMA in Flash */
Here, > RAM defines the execution address, while AT > FLASH tells the linker where to store the initial data in the binary image.
Completing the Handover
The linker provides the symbols _sdata and _edata (and a symbol representing the start of data in Flash, often _sidata), which the startup assembly code uses. Before jumping to main(), your startup code must execute a simple memcpy or loop to copy the data from the Flash address to the RAM address. If this initialization step is omitted or configured incorrectly, your global variables will contain garbage data instead of your intended initial values.
Key Takeaway: You must explicitly map the .data section to both a load address in Flash and a virtual address in RAM, then use your startup code to copy these initial values into RAM before executing the application.