链接器工作过程及链接脚本文件 .lds
分析
Linker
链接器将多目标文件生成最终可执行文件,示意图如下
在链接过程中执行如下操作
- Symbol Resolution - 符号解析
- 多文件声明与调用
- 调用替换为具体函数入口
- Relocation - 重定位
- 相同段合并,例如
.text
- Section Placement, 各段在内存中的位置
- 相同段合并,例如
详细解释见 Linker
Linker Script File
控制链接器行为的脚本文件,一般后缀为 .lds
。如果不指定,存在默认脚本,使用 ld --verbose
查看
SECTIONS { ❶
. = 0x00000000; ❷
.text : { ❸
abc.o (.text);
def.o (.text);
}
}
SECTIONS
脚本各段组成及位置.
定位器符号.text
由abc.o
和def.o
中的.text
组成
LMA vs VMA
LMA
(load memory address 加载内存地址或进程地址空间地址)VMA
(virtual memory address 虚拟内存地址或程序地址空间地址)
VMA 是执行输出文件时 section 所在的地址,而 LMA 是加载输出文件时 section 所在的地址。一般而言,某 section 的 VMA == LMA. 但在嵌入式系统中,经常存在加载地址和执行地址不同的情况:比如将输出文件加载到开发板的 flash 中(由 LMA 指定), 而在运行时将位于 flash 中的输出文件复制到 SDRAM 中(由 VMA 指定)。
SECTIONS 命令
SECTIONS
命令告诉 ld 如何把输入文件的 sections 映射到输出文件的各个 section: 如何将输入 section 合为输出 section; 如何把输出 section 放入 VMA 和 LMA
SECTIONS
{
SECTIONS-COMMAND
SECTIONS-COMMAND
...
}
SECTION-COMMAND 有四种:
- ENTRY 命令
- 符号赋值语句
- 一个输出 section 的描述 (output section description)
- 一个 section 叠加描述 (overlay description)
ENTRY 命令
将符号 SYMBOL
的值设置成入口地址
ENTRY(SYMBOL)
符号赋值
- 对符号的赋值只对全局变量起作用
- 赋值语句包含 4 个语法元素:符号名、操作符、表达式、分号;一个也不能少
.
是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置。该符号只能在 SECTIONS 命令内使用
叠加描述
覆盖图描述使两个或多个不同的 section 占用同一块程序地址空间。覆盖图管理代码负责将 section 的拷入和拷出。
输出描述
格式如下
SECTION-NAME [ADDRESS] [(TYPE)] : [AT(LMA)]
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
…
} [>REGION] [AT>LMA_REGION] [:PHDR HDR ...] [=FILLEXP]
ALIGN
地址对齐- 文件通配符
.
定位符KEEP
AT
修改 LMA>REGION
修改 VMA
MEMORY 命令
在默认情形下,连接器可以为 section 在程序地址空间内分配任意位置的存储区域。并通过输出 section 描述的 >REGION
属性显示地将该输出 section 限定于在程序地址空间内的某块存储区域,当存储区域大小不能满足要求时,连接器会报告该错误。
MEMORY
{
NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2
...
}
Example
MEMORY
{
sram : ORIGIN = 0x00100000, LENGTH = 0x8000
ddram : ORIGIN = 0x80000000, LENGTH = 0x100000
}
ENTRY(ResetEntry)
SECTIONS {
. = ALIGN(4);
.text :
{
sram/*(.text*)
sram/*(.data*)
sram/*(.rodata*)
*(.reset_patch)
*(.sram_text)
*(.sram)
} > sram
. = ALIGN(0x8000);
.data :
{
*(.text*)
. = ALIGN(4);
*(.data*)
*(.rodata*)
. = ALIGN(16);
} > ddram
. = ALIGN(4);
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > ddram
}