Home / Tutorials / STM32 Tutorial / What are Linker Files in STM32?
pcbway

What are Linker Files in STM32?

Linker scripts play a crucial role in STM32 firmware development by defining how the compiler organizes the program in memory. Understanding linker files is essential for embedded engineers working with STM32 microcontrollers, as it allows them to control memory layout, define sections, and optimize RAM/Flash usage.

This tutorial will cover:

  1. What is a Linker File?
  2. Understanding the STM32 Memory Layout
  3. Structure of a Linker Script (.ld file)
  4. Common Sections in an STM32 Linker Script
  5. Modifying a Linker Script
  6. Practical Example: Customizing RAM and Flash
  7. Debugging and Troubleshooting Linker Errors

1. What is a Linker File?

A linker file (.ld file) is a script used by the GNU linker (ld) to define the memory regions of a microcontroller and specify where different parts of the program should be placed in memory.

In STM32 projects, the linker file tells the compiler where to place:

  • The startup code
  • The main application code
  • Global/static variables
  • Heap and stack memory

2. Understanding the STM32 Memory Layout

STM32 microcontrollers typically have two main types of memory:

  • Flash Memory (Non-volatile)
    Stores the program (code and constants). Flash is usually located at 0x08000000.

  • RAM (Volatile)
    Stores variables, stack, and heap. RAM is typically located at 0x20000000.

Example memory layout for an STM32F103C8T6 (64 KB Flash, 20 KB RAM):

Region Start Address Size
Flash 0x08000000 64 KB
RAM 0x20000000 20 KB

3. Structure of a Linker Script (.ld file)

A typical STM32 linker script is divided into sections:

1. Header and Memory Definition

Defines the memory regions (Flash, RAM) available in the microcontroller.

MEMORY 
{ 
    FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K 
    RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K 
}
  • rx : Flash is readable (r) and executable (x).
  • rwx: RAM is readable, writable, and executable (rwx).

2. Entry Point Definition

Defines where execution starts.

ENTRY(Reset_Handler)

The Reset_Handler is defined in startup_stm32.s and is the first function executed after a reset.

3. Sections Definition

Organizes program sections into memory.

SECTIONS
{
   /* Code and Read-Only Data in Flash */
   .text :
   {
      KEEP(*(.isr_vector)) /* Interrupt Vector Table */
      *(.text*) /* Code */
      *(.rodata*) /* Read-only data */
      . = ALIGN(4);
   } > FLASH

   /* Initialized Data in RAM */
   .data :
   {
      *(.data*) /* Initialized global/static variables */
      . = ALIGN(4);
   } > RAM AT> FLASH

   /* Uninitialized Data in RAM */
   .bss :
   {
      *(.bss*) /* Uninitialized global/static variables */
      . = ALIGN(4);
   } > RAM

   /* Stack and Heap */
   _estack = ORIGIN(RAM) + LENGTH(RAM);
   _Min_Heap_Size = 0x100; /* Minimum heap size */
   _Min_Stack_Size = 0x400; /* Minimum stack size */
}

4. Common Sections in an STM32 Linker Script

Here’s a breakdown of important sections:

Section Description Location
.text Code (functions, ISRs) Flash
.rodata Read-only data (constants, strings) Flash
.data Initialized variables RAM (loaded from Flash)
.bss Uninitialized variables RAM
.heap Dynamic memory (malloc/free) RAM
.stack Call stack for function calls RAM

5. Modifying a Linker Script

1. Increasing the Stack Size

To change the stack size, modify _Min_Stack_Size:

_Min_Stack_Size = 0x800; /* Increase stack size to 2 KB */

2. Placing a Variable at a Specific Address

If you need a variable at a fixed RAM location:

__attribute__((section(".my_section"))) int my_var = 42;

Then add this section to the linker script:

.my_section : { *(.my_section) } > RAM

3. Allocating a Bootloader Region

If using a bootloader (e.g., 16 KB at the beginning of Flash), adjust Flash origin:

MEMORY
{
   FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 48K /* Bootloader takes first 16 KB */
   RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}

6. Practical Example: Customizing RAM and Flash

Suppose we want to:

  • Allocate a special section for a DMA buffer
  • Reserve memory for a bootloader

1. Define a Special Section for DMA Buffer

In main.c:

__attribute__((section(".dma_buffer"))) uint8_t dmaBuffer[1024];

In STM32F103_FLASH.ld:

.dma_buffer (NOLOAD) : 
{ 
   *(.dma_buffer) 
} > RAM

(NOLOAD prevents initialization in .data or .bss.)

2. Modify Flash for Bootloader

Modify memory layout:

MEMORY 
{ 
   FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 48K 
   RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K 
}

7. Debugging and Troubleshooting Linker Errors

1. Common Errors

Error Cause Solution
undefined reference to symbol Missing function definition Ensure correct file is linked
section .data will not fit in region RAM Not enough RAM Reduce .data size or increase RAM size
heap region overflow Heap too large Reduce heap size (_Min_Heap_Size)

2. Check Memory Usage

Use arm-none-eabi-size:

arm-none-eabi-size -B firmware.elf

Example output:

text data bss dec hex filename 13500 800 3000 17300 439c firmware.elf
  • text → Code size
  • data → Initialized data in RAM
  • bss → Uninitialized variables

Conclusion

Linker scripts are a critical part of STM32 firmware development, defining how memory is allocated and structured. By understanding and modifying linker files, you can:

  • Optimize memory usage
  • Relocate sections
  • Implement bootloaders and special memory mappings

Mastering linker scripts helps ensure efficient and reliable embedded software development for STM32 microcontrollers.

Check Also

STM32F4 Waveform Generation using DAC

Generating Sine, Triangular, and Sawtooth Waveforms using STM32F4 DAC

The STM32F4 microcontroller series is popular in embedded systems applications due to its powerful features. …

Index