跳到主要内容

4. 与 GNU ld 的行为差异

KF32 LLVM 工具链采用定制过的 LLD 链接器。脚本语法(MEMORY / SECTIONS / KEEP / PROVIDE / DEFINED / SORT / NOLOAD / ORIGIN / LENGTH 等)与 GNU ld 基本兼容,但以下行为存在差异,编写或修改脚本时需特别注意:

#差异点影响规避方式
1定位计数器 . 为绝对地址语义漏加 ORIGIN 导致布局错乱区域内赋值一律显式加 ORIGIN(...);预留空间改用 . = . + 长度
2孤儿段处理不同未列出的输入段直接报错脚本显式覆盖所有输入段
3装载地址与 NOLOAD 需显式声明合并段中的 .bss / 堆栈也写入 Flash;.data 缺 AT > flash 时 HEX 阶段报错.data 用 > ram AT > flash;.bss / .heap / .stack 拆分并标 (NOLOAD)
4库文件自动迭代符号成环无需 --start-group无需处理(传入亦兼容)

4.1 定位计数器 . 的语义​

GNU ld 中段内的 . 表示相对该段起始的偏移;LLD 中 . 是绝对地址语义,. = 数值 直接设定绝对地址。因此凡是为 . 或符号赋一个区域内的目标地址时,都必须显式加上 ORIGIN:

__initial_sp = ORIGIN(ram) + LENGTH(ram); /* RAM 顶地址:必须加 ORIGIN(ram) */
. = ORIGIN(ram) + 0x8000 ; /* lpdata 占满保持区 32K:必须加 ORIGIN(ram) */
. = ORIGIN(flash) + 0x200; /* flash 内偏移 0x200:必须加 ORIGIN(flash) */
注意

漏加 ORIGIN 表现为链接阶段报错:unable to move location counter backward for: <段名>;若赋值行落在参与松弛(relaxation)的代码段内,则报输入段重叠 relaxation: overlapping input sections in <段名> …。任何情况下修改脚本都要核对区域内的赋值是否加上了 ORIGIN。

4.1.1 相对推进:. = . + 长度​

如果只是从当前位置向后预留空间,不需要指定绝对地址,可以对 . 做相对推进:

. = . + 0x100; /* 从当前位置起预留 0x100 字节;等价写法 . += 0x100; */

右值中的 . 取当前地址,因此这种写法在 GNU ld 与 LLD 下语义一致,也无须 ORIGIN;为子区预留固定长度时优先使用,不会因区域起始地址变化而失效。

4.2 孤儿段检查​

脚本中未显式列出的输入段称为孤儿段。使用含 SECTIONS 命令的链接脚本时,孤儿段导致链接失败,报错如下:

kf32ld: error: unplaced orphan section '.mysec' from 'main.o'

unplaced orphan section 表示该段未被链接脚本放置;引号内依次为段名(.mysec)与来源文件(main.o),段来自库成员时来源显示为库文件名加成员名,如 libfoo.a(foo.o)。未覆盖的输入段若由链接器自动放置,可能落到不符合预期的地址,造成数据覆盖或运行异常,因此按错误处理。

脚本应显式覆盖所有预期的输入段(含调试段)。

4.3 装载地址与 NOLOAD​

从 GNU ld 工程迁移时,.data、.bss 与堆栈常合并在同一输出段,并用 AT(__text_end__) 指定装载地址。LLD 按输出段整体生成装载映像:段内所有内容(包括 .bss 与堆栈)都会进入 Flash,HEX 明显膨胀;LLD 也不会因为段名是 .bss / .heap / .stack 就自动按不装载处理。

迁移时应拆成独立输出段:

.data : { … } > ram AT > flash
.bss (NOLOAD) : { … } > ram
.heap (NOLOAD) : { … } > ram
.stack (NOLOAD) : { … } > ram

.bss / .heap / .stack 必须显式标注 (NOLOAD),否则按普通已初始化段处理,未使用空间以 0 填充写入 HEX。.data 必须显式声明装载区域:去掉 AT > flash 后 LLD 仍能完成链接(LMA = VMA),但 kf32objcopy 生成 HEX 时报错:

__data_start__, __data_end__, __bss_start__, and __bss_end__ must be defined in section .data

若沿用迁移前的合并段写法且未声明装载地址,链接与 HEX 均能生成,但 HEX 中不含 .data 初值映像。

4.4 库文件的自动迭代​

  • GNU ld 对归档库按命令行顺序单遍扫描,符号出现循环依赖时需要 --start-group / --end-group(或 -Wl,--start-group)包裹。
  • LLD 会自动重复扫描归档直至无新符号引入,无需 group;命令行中传入 --start-group / --end-group 亦兼容,不会报错。