链接器
将经过编译或者汇编的二进制文件(.o文件) 生成可执行二进制文件。
例如GNU Linker,提供一个链接命令ld,常用的链接选项如下:
选项 | 注释 |
---|---|
-T | 指定链接脚本 |
-Map | 输出一个符号表文件 |
-o | 输出最终可执行二进制文件 |
-b | 指定目标代码输入文件的格式 |
-e | 使用指定的符号作为程序的初始执行点 |
-l | 把指定的库文件添加到要链接的文件清单中 |
-L | 把指定的路径添加到搜索库的目标清单中 |
-S | 忽略来自输出文件的调试器符号信息 |
-s | 忽略来自输出文件的所有符号信息 |
-t | 在处理输入文件时显示它们的名称 |
-Ttext | 使用指定的地址作为代码段的起点 |
-Tdata | 使用指定的地址作为数据段的起点 |
-Tbss | 使用指定的地址作为未初始化的数据段的起点 |
-Bstatic | 只使用静态库 |
-Bdynamic | 只使用动态库 |
-defsym | 在输出文件中定义指定的全局符号 |
链接脚本
链接器的链接过程由一个链接脚本控制,该脚本使用链接器命令语言编写,主要用于规定各输入文件中的程序、数据等内容段在输出文件中的空间和地址如何分配。
如果没有通过 “-T” 参数指定链接脚本时,链接器会使用内置的链接脚本。
常用语法汇总
定位符.
定位符.
表示当前地址,根据 section 的大小不断增加,不能倒退。对定位符.
赋值可修改当前地址,指定其后内容的存储位置,如果没有以其它的方式指定输出节的地址,则地址值会根据定位器的当前值计算。
. = 0x1000;
.text :
{}
. = 0x2000;
.rodata :
{}
先修改起始地址为 0x1000,指定 text 段从当前位置存储;再修改当前地址为 0x2000,指定 rodata 段的存储位置。
ENTRY
ENTRY(SYMBOL) :将符号 SYMBOL 对应的地址设置成程序入口地址。常见的实例比如:ENTRY(_start),表示程序从 _start 处开始运行。设置程序入口的方法有好几种,根据优先级从高到低依次为:
- ld 命令行的 -e 选项
- 链接脚本的ENTRY(SYMBOL)命令
- 在汇编程序中定义了 _start 符号,使用 _start 符号值(如.global _start)
- 如果存在 .text section,使用 .text section 首地址的值
- 从地址 0 开始运行
MEMORY
MEMORY
{
NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2
}
MEMORY声明一个或多个内存区域,名称必须唯一,其属性指定该区域是否可以写入、读取或执行。
ATTR属性支持7种模式:
- R 只读section
- W 读/写section
- X 可执行section
- A 可分配的section
- I 初始化了的section
- L 同 I
- ! 反转以上任何属性
常见的内存设置一般有一个flash和一个sram区域:
MEMORY
{
flash (rxa) : ORIGIN = 0x80000000, LENGTH = 128K
sram (wxa) : ORIGIN = 0x20000000, LENGTH = 32K
}
SECTIONS
SECTIONS
{
secname [VMA_ADDR] [(TYPE)] : [AT (LMA_ADDR)]
{
contents
} [>VMA_REGION] [AT>LMA_REGION] [:PHDR HDR ...] [=FILLEXP]
}
- secname
表示输出文件的段名,后面必须紧跟一个空格,使用冒号**:**分割 - contents
描述该段的内容包括哪些文件、符号 - TYPE
每个输出section都有一个类型,如果没有指定TYPE类型,那么连接器根据输出section引用的输入section的类型设置该输出section的类型。例如 NOLOAD,表示该section在程序运行时,不被载入内存。 - VMA_REGION
对应 MEMORY 定义的内存区域。 - LMA_REGION
对应 MEMORY 定义的内存区域。 - VMA_ADDR
虚地址,即输出文件VMA(运行地址)。表示将该段强制链接到的地址,会改变定位符.
的值。 - LMA_ADDR
加载地址,即数据实际存储的地。表示该段的 LMA(加载地址),默认情况下 LMA = VMA。数据段加载时会存至 Flash 中(使用LMA地址),运行时将其搬运到 RAM(使用VMA地址)。
.text :
{
} >flash AT>flash
.bss :
{
} >flash AT>sram
ALIGN
表示字节对齐, 如. = ALIGN(4)
表示从该地址开始后面的存储内容进行4字节对齐。
PROVIDE
定义一个符号,相当于定义一个全局变量的符号表,其他C文件可以通过该符号来操作对应的存储内存。程序中可以先使用该符号,虽然此时未定义,但是链接时会识别到该符号。
KEEP
当链接器使用–gc-sections进行垃圾回收时,链接器可能将某些它认为没用的 section 过滤掉,此时就有必要强制让链接器保留一些特定的 section,KEEP()可以使得被标记section的内容不被清除(即防止被优化)。