Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 440 of 9366. Embedded Software Construction and ToolchainsFree lesson

Managing Load and Virtual Address Differences

You will configure the linker to handle cases where code resides in Flash but executes from RAM using VMA and LMA.

In this lesson, you will learn how to configure the linker script to distinguish between where code is physically stored (Load Memory Address) and where it is expected to execute (Virtual Memory Address).

The Dual-Address Reality

In many embedded systems, executing code directly from Flash is slower than running it from internal SRAM. To boost performance, we often copy time-critical functions from Flash to RAM during system initialization. This requires the linker to manage two distinct addresses for the same section of code:

  1. LMA (Load Memory Address): The physical location in Flash where the binary resides when the device is powered off.
  2. VMA (Virtual Memory Address): The target address in RAM where the CPU expects the code to be located during execution.

Configuring the Linker Script

To achieve this, we use the AT command within the linker script's section definition. This tells the linker that the section should be loaded at one location but linked for execution at another.

Consider a hot function section called .fast_code:

MEMORY {
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
  SRAM  (rwx): ORIGIN = 0x20000000, LENGTH = 64K
}

SECTIONS {
  .fast_code : {
    . = ALIGN(4);
    _sfast_code = .;     /* Start of VMA in RAM */
    *(.fast_code)
    _efast_code = .;     /* End of VMA in RAM */
  } > SRAM AT > FLASH    /* VMA is SRAM, LMA is FLASH */
}

In this setup, the AT > FLASH keyword instructs the linker to place the data in Flash immediately following the previous section, while the > SRAM tells the linker to generate addresses relative to the RAM base.

The Initialization Requirement

Simply defining the VMA and LMA in the linker script is not enough to make it work. Because the data physically resides in Flash, you must manually copy it from the LMA to the VMA during your startup code (usually in Reset_Handler). Using the symbols _sfast_code, _efast_code, and a corresponding linker-provided symbol for the Flash address, you use a memcpy operation to move the binary blob into RAM before the CPU ever attempts to jump to those virtual addresses. If you skip this copy step, the CPU will jump to an uninitialized RAM location, leading to a hard fault.

Key Takeaway: By using the AT keyword in your linker script, you decouple a section’s storage address from its execution address, allowing you to bridge the speed gap between slow non-volatile storage and high-speed RAM.