裸机程序用lld链接必须显式指定入口符号_start,否则复位向量指向0x0导致无反应或hardfault;memory块属性需严格匹配硬件(如flash(rx)、ram(rwx));.data段须用at>分离lma/vma以支持加载与运行地址不同。

lld链接裸机程序必须显式指定入口符号,否则默认找不到 _start
裸机程序没有操作系统接管启动流程,lld 不会自动识别 main 或其他函数为入口。它只认链接脚本里 ENTRY() 指定的符号,或命令行传入的 -e _start。如果没设,链接会成功但复位向量指向 0x0,运行时直接跳到无效地址——现象是芯片上电无反应,或进 HardFault。
正确做法是二者选一:
- 在链接脚本中写
ENTRY( _start )(注意下划线,且与汇编启动文件里定义的符号名严格一致) - 编译命令里加
-Wl,-e,_start(-Wl把参数透传给 lld)
别用 main 当入口:裸机没有 C 运行时环境(crt0),main 的调用链依赖栈初始化、.data 复制、.bss 清零等,这些都得靠 _start 手动完成。
MEMORY 块定义必须匹配芯片手册的 Flash/RAM 地址和长度,attr 字段不能乱填
lld 解析链接脚本时对 MEMORY 块的 attr 是严格校验的。比如你写 RAM (rwx),但实际 RAM 不支持执行(X),某些 Cortex-M 系列会因 MPU 配置或硬件限制导致跳转失败;反过来,Flash 标成 w(可写)而没开编程权限,后续擦写操作会出错。
典型 MCU 的写法应为:
MEMORY {
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
关键点:
-
FLASH至少带r和x,否则代码无法读取和执行 -
RAM要带w(.data 初始化、.bss 清零、栈都需要写) - 不要加
!w或!x这类取反属性——lld 不支持,会报错unknown memory region attribute - 地址和长度必须和数据手册完全一致,差 1 字节都可能导致 .text 溢出或 .stack 覆盖堆区
SECTIONS 中的 .text、.data、.bss 必须显式分配到 MEMORY 区域,且注意 LMA/VMA 分离
裸机程序的 .data 段需要“加载时在 Flash,运行时在 RAM”——即 LMA(Load Memory Address)在 FLASH,VMA(Virtual Memory Address)在 RAM。lld 默认把二者设为相同地址,不手动分离会导致 .data 内容被当成代码执行,或者初始化失败。
正确写法示例:
SECTIONS {
.text : {
*(.text .text.*)
} > FLASH
.data : {
__data_load_start = LOADADDR(.data);
__data_start = .;
*(.data .data.*)
__data_end = .;
} > RAM AT> FLASH
.bss : {
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
} > RAM
}
说明:
-
> RAM AT> FLASH明确分离了 VMA(RAM)和 LMA(FLASH) -
LOADADDR(.data)是 lld 提供的内置函数,返回该段 LMA 起始地址,供 C 启动代码复制 .data 使用 -
.bss只需指定 VMA(> RAM),因为它运行前要清零,不需要从 Flash 加载 - 所有符号如
__data_start必须用PROVIDE或直接赋值定义,否则 C 代码里 extern 声明后链接时报undefined reference
使用 lld 而非 ld 时,链接脚本语法基本兼容,但忽略 GNU ld 特有扩展
lld 支持绝大多数 GNU ld 脚本语法,包括 ENTRY、MEMORY、SECTIONS、PROVIDE、ALIGN 等。但它不支持:
-
INSERT AFTER/BEFORE—— lld 无此指令,需靠 section ordering 控制顺序 -
INCLUDE嵌套路径若含空格或相对路径不规范,lld 解析可能失败(建议全用绝对路径或扁平化脚本) - 某些 GNU ld 的 magic 符号如
__CTOR_LIST__,lld 默认不生成,需手动定义或改用__attribute__((constructor))替代
验证是否生效最直接的方式:链接后跑 llvm-readobj -sections your.elf,检查各段的 VirtualAddress(VMA)和 FileOffset(对应 LMA)是否符合预期——这是最容易被跳过、却决定程序能否跑起来的关键一步。











