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:
- What is a Linker File?
- Understanding the STM32 Memory Layout
- Structure of a Linker Script (.ld file)
- Common Sections in an STM32 Linker Script
- Modifying a Linker Script
- Practical Example: Customizing RAM and Flash
- 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.
- rx : Flash is readable (r) and executable (x).
- rwx: RAM is readable, writable, and executable (rwx).
2. Entry Point Definition
Defines where execution starts.
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:
2. Placing a Variable at a Specific Address
If you need a variable at a fixed RAM location:
Then add this section to the linker script:
3. Allocating a Bootloader Region
If using a bootloader (e.g., 16 KB at the beginning of Flash), adjust Flash origin:
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:
In STM32F103_FLASH.ld:
(NOLOAD prevents initialization in .data or .bss.)
2. Modify Flash for Bootloader
Modify memory layout:
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:
Example output:
- 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.