linker-scripts

Guide agents through writing and modifying GNU ld linker scripts for embedded targets: MEMORY and SECTIONS commands, VMA vs LMA for code relocation, startup .bss /.data initialization, placing sections in specific regions, and using PROVIDE/KEEP/ALIGN directives.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "linker-scripts" with this command: npx skills add mohitmishra786/low-level-dev-skills/mohitmishra786-low-level-dev-skills-linker-scripts

Linker Scripts

Purpose

Guide agents through writing and modifying GNU ld linker scripts for embedded targets: MEMORY and SECTIONS commands, VMA vs LMA for code relocation, startup .bss /.data initialization, placing sections in specific regions, and using PROVIDE/KEEP/ALIGN directives.

Triggers

  • "How do I write a linker script for my MCU?"

  • "How do I place a function in a specific flash/RAM region?"

  • "What's the difference between VMA and LMA in a linker script?"

  • "How does .bss and .data initialization work at startup?"

  • "Linker error: region 'FLASH' overflowed"

  • "How do I use weak symbols in a linker script?"

Workflow

  1. Linker script anatomy

/* Minimal Cortex-M linker script */

ENTRY(Reset_Handler) /* entry point symbol */

MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K }

SECTIONS { .text : /* code section / { KEEP((.isr_vector)) /* interrupt vector must be first */ *(.text) (.text.) (.rodata) (.rodata.) . = ALIGN(4); _etext = .; / end of flash content */ } > FLASH

.data : AT(_etext)          /* VMA = RAM, LMA = FLASH */
{
    _sdata = .;
    *(.data)
    *(.data.*)
    . = ALIGN(4);
    _edata = .;
} > RAM

.bss :
{
    _sbss = .;
    *(.bss)
    *(.bss.*)
    *(COMMON)
    . = ALIGN(4);
    _ebss = .;
} > RAM

/* Stack at top of RAM */
_estack = ORIGIN(RAM) + LENGTH(RAM);

}

  1. VMA vs LMA
  • VMA (Virtual Memory Address): where the section runs at runtime

  • LMA (Load Memory Address): where the section is stored in the image (flash)

For .data : stored in flash (LMA), copied to RAM at startup (VMA).

/* AT() sets LMA explicitly */ .data : AT(ADDR(.text) + SIZEOF(.text)) { _sdata = .; (.data) _edata = .; } > RAM / VMA goes in RAM */

LMA of .data is automatically placed after .text if you use AT(_etext) .

  1. Startup .bss / .data initialization

The C runtime must copy .data from flash to RAM and zero .bss before main() :

// startup.c or startup.s equivalent in C extern uint32_t _sdata, _edata, _sidata; // _sidata = LMA of .data extern uint32_t _sbss, _ebss;

void Reset_Handler(void) { // Copy .data from flash to RAM uint32_t *src = &_sidata; uint32_t *dst = &_sdata; while (dst < &_edata) *dst++ = *src++;

// Zero-initialize .bss
dst = &#x26;_sbss;
while (dst &#x3C; &#x26;_ebss) *dst++ = 0;

// Call C++ constructors
// (call __libc_init_array() if using newlib)

main();
for (;;);  // should never return

}

Linker script provides _sidata (LMA of .data ):

.data : AT(_etext) { _sdata = .; *(.data) _edata = .; } > RAM

_sidata = LOADADDR(.data); /* LMA of .data for startup code */

  1. Placing code in specific regions

/* Place time-critical code in RAM for faster execution / MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx): ORIGIN = 0x20000000, LENGTH = 128K CCM (rwx): ORIGIN = 0x10000000, LENGTH = 64K / Cortex-M4 CCM */ }

.fast_code : AT(_etext) { _sfast = .; (.fast_code) / sections marked attribute((section(".fast_code"))) / _efast = .; } > CCM / runs from CCM RAM */

// Mark a function to go in fast_code section attribute((section(".fast_code"))) void critical_isr_handler(void) { // runs from CCM RAM }

  1. KEEP, ALIGN, PROVIDE

/* KEEP — prevent garbage collection of section / KEEP((.isr_vector)) /* linker gc won't remove interrupt table / KEEP((.init)) KEEP(*(.fini))

/* ALIGN — advance location counter to alignment boundary / . = ALIGN(8); / align to 8 bytes */

/* PROVIDE — define symbol only if not already defined (weak default) / PROVIDE(_stack_size = 0x400); / default 1KB stack; override in code */

/* Symbols for stack */ .stack : { . = ALIGN(8); . += _stack_size; _stack_top = .; } > RAM

/* FILL — fill unused bytes */ .text : { (.text) . = ALIGN(4); FILL(0xFF) / fill flash gaps with 0xFF (erased state) */ } > FLASH

  1. Weak symbols

/* In linker script — provide weak default ISR */ PROVIDE(NMI_Handler = Default_Handler); PROVIDE(HardFault_Handler = Default_Handler); PROVIDE(SysTick_Handler = Default_Handler);

// In C — weak default handler attribute((weak)) void Default_Handler(void) { for (;;); // spin — override this in application }

// Override by defining a non-weak symbol with the same name void SysTick_Handler(void) { tick_count++; }

  1. Common linker errors

Error Cause Fix

region 'FLASH' overflowed

Binary too large for flash Enable LTO, -Os , remove unused code; --gc-sections

region 'RAM' overflowed

Too much RAM used Reduce stack size, use static buffers, check .bss size

undefined reference to '_estack'

Missing linker script symbol Define _estack in linker script

no rule to process file

.ld extension not recognized Pass with -T script.ld

cannot find linker script

Wrong path Use -L dir -T name.ld

Data section .data at wrong address LMA not set Add AT(_etext) after .data section definition

Analyze section sizes

arm-none-eabi-size firmware.elf arm-none-eabi-size -A firmware.elf # verbose per-section

Show all sections and their addresses

arm-none-eabi-objdump -h firmware.elf

Check if .data LMA is in flash range

arm-none-eabi-readelf -S firmware.elf | grep -A2 ".data"

For linker script anatomy details, see references/linker-script-anatomy.md.

Related skills

  • Use skills/embedded/openocd-jtag for flashing to addresses defined in linker script

  • Use skills/embedded/freertos for FreeRTOS heap placement in specific RAM regions

  • Use skills/binaries/linkers-lto for linker LTO and symbol flags

  • Use skills/binaries/elf-inspection to inspect section sizes and addresses

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

cmake

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

static-analysis

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

llvm

No summary provided by upstream source.

Repository SourceNeeds Review