linker-scripts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLinker 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 / initialization, placing sections in specific regions, and using PROVIDE/KEEP/ALIGN directives.
.bss.data指导开发者编写和修改面向嵌入式目标的GNU ld链接脚本:包括MEMORY与SECTIONS命令、用于代码重定位的VMA与LMA、启动阶段的/初始化、将段放置到特定区域,以及使用PROVIDE/KEEP/ALIGN指令。
.bss.dataTriggers
触发场景
- "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?"
- "如何为我的MCU编写链接脚本?"
- "如何将函数放置到特定的Flash/RAM区域?"
- "链接脚本中的VMA和LMA有什么区别?"
- "启动阶段的.bss和.data初始化是如何工作的?"
- "链接错误:region 'FLASH' overflowed"
- "如何在链接脚本中使用弱符号?"
Workflow
工作流程
1. Linker script anatomy
1. 链接脚本结构
ld
/* 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);
}ld
/* 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);
}2. VMA vs LMA
2. VMA与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 : stored in flash (LMA), copied to RAM at startup (VMA).
.datald
/* AT() sets LMA explicitly */
.data : AT(ADDR(.text) + SIZEOF(.text))
{
_sdata = .;
*(.data)
_edata = .;
} > RAM /* VMA goes in RAM */LMA of is automatically placed after if you use .
.data.textAT(_etext)- VMA(Virtual Memory Address,虚拟内存地址):段在运行时所在的地址
- LMA(Load Memory Address,加载内存地址):段在镜像(Flash)中存储的地址
对于段:存储在Flash(LMA)中,启动时复制到RAM(VMA)。
.datald
/* AT() sets LMA explicitly */
.data : AT(ADDR(.text) + SIZEOF(.text))
{
_sdata = .;
*(.data)
_edata = .;
} > RAM /* VMA goes in RAM */如果使用,的LMA会自动放置在之后。
AT(_etext).data.text3. Startup .bss / .data initialization
3. 启动阶段的.bss / .data初始化
The C runtime must copy from flash to RAM and zero before :
.data.bssmain()c
// 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 = &_sbss;
while (dst < &_ebss) *dst++ = 0;
// Call C++ constructors
// (call __libc_init_array() if using newlib)
main();
for (;;); // should never return
}Linker script provides (LMA of ):
_sidata.datald
.data : AT(_etext)
{
_sdata = .;
*(.data)
_edata = .;
} > RAM
_sidata = LOADADDR(.data); /* LMA of .data for startup code */C运行时必须在之前将从Flash复制到RAM,并将清零:
main().data.bssc
// 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 = &_sbss;
while (dst < &_ebss) *dst++ = 0;
// Call C++ constructors
// (call __libc_init_array() if using newlib)
main();
for (;;); // should never return
}链接脚本提供(的LMA):
_sidata.datald
.data : AT(_etext)
{
_sdata = .;
*(.data)
_edata = .;
} > RAM
_sidata = LOADADDR(.data); /* LMA of .data for startup code */4. Placing code in specific regions
4. 将代码放置到特定区域
ld
/* 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 */c
// Mark a function to go in fast_code section
__attribute__((section(".fast_code")))
void critical_isr_handler(void) {
// runs from CCM RAM
}ld
/* 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 */c
// Mark a function to go in fast_code section
__attribute__((section(".fast_code")))
void critical_isr_handler(void) {
// runs from CCM RAM
}5. KEEP, ALIGN, PROVIDE
5. KEEP、ALIGN、PROVIDE
ld
/* 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) */
} > FLASHld
/* 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) */
} > FLASH6. Weak symbols
6. 弱符号
ld
/* In linker script — provide weak default ISR */
PROVIDE(NMI_Handler = Default_Handler);
PROVIDE(HardFault_Handler = Default_Handler);
PROVIDE(SysTick_Handler = Default_Handler);c
// 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++;
}ld
/* In linker script — provide weak default ISR */
PROVIDE(NMI_Handler = Default_Handler);
PROVIDE(HardFault_Handler = Default_Handler);
PROVIDE(SysTick_Handler = Default_Handler);c
// 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++;
}7. Common linker errors
7. 常见链接错误
| Error | Cause | Fix |
|---|---|---|
| Binary too large for flash | Enable LTO, |
| Too much RAM used | Reduce stack size, use static buffers, check |
| Missing linker script symbol | Define |
| | Pass with |
| Wrong path | Use |
Data section | LMA not set | Add |
bash
undefined| 错误 | 原因 | 修复方法 |
|---|---|---|
| 二进制文件过大,超出Flash容量 | 启用LTO、 |
| RAM使用量过大 | 减小栈大小,使用静态缓冲区,检查 |
| 缺少链接脚本符号 | 在链接脚本中定义 |
| | 使用 |
| 路径错误 | 使用 |
Data section | 未设置LMA | 在 |
bash
undefinedAnalyze section sizes
Analyze section sizes
arm-none-eabi-size firmware.elf
arm-none-eabi-size -A firmware.elf # verbose per-section
arm-none-eabi-size firmware.elf
arm-none-eabi-size -A firmware.elf # verbose per-section
Show all sections and their addresses
Show all sections and their addresses
arm-none-eabi-objdump -h firmware.elf
arm-none-eabi-objdump -h firmware.elf
Check if .data LMA is in flash range
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](references/linker-script-anatomy.md).arm-none-eabi-readelf -S firmware.elf | grep -A2 ".data"
有关链接脚本结构的详细信息,请参阅[references/linker-script-anatomy.md](references/linker-script-anatomy.md)。Related skills
相关技能
- Use for flashing to addresses defined in linker script
skills/embedded/openocd-jtag - Use for FreeRTOS heap placement in specific RAM regions
skills/embedded/freertos - Use for linker LTO and symbol flags
skills/binaries/linkers-lto - Use to inspect section sizes and addresses
skills/binaries/elf-inspection
- 使用将程序烧写到链接脚本定义的地址
skills/embedded/openocd-jtag - 使用在特定RAM区域放置FreeRTOS堆
skills/embedded/freertos - 使用配置链接器LTO和符号标志
skills/binaries/linkers-lto - 使用检查段大小和地址
skills/binaries/elf-inspection