目录
链接脚本原理
每一个链接过程都由链接脚本 (linker script,一般以 lds 作为文件的后缀名) 控制。
链接脚本主要用于规定如何把输入文件内的 section 放入输出文件内,并控制输出文件
内容各部分在程序地址空间内布局。链接器有个默认的内置链接脚本,可以使用
ld -verbose 查看。ld 链接选项 -r 和 -N 可以影响默认的链接脚本,-T 选项用以指定
特定的链接脚本,它将代替默认的链接脚本。也可以使用暗含的链接脚本以增加自定义的
链接命令。
基本概念
链接器把一个或多个输入文件合成一个输出文件。
目标文件 (包括可执行文件) 具有固定的格式,在 UNIX 或者 GNU/Linux 平台下,一般
为 ELF 格式。把输入文件的 section 称为输入 section (input section),把输出文件
内的 section 称为输出 section (output section)。
目标文件的每个 section 至少包含两个信息:名字和大小。大部分 section 还包含于它
相关联的一块数据,称为 section contents (section 内容)。 一个 section可被标记
为 loadable (可加载的) 或 allocatable (可分配的)。
如果一个 section 不是 “可加载的”或 “可分配的”,那么该 section 通常包含调试信
息,可用 objdump -h 命令查看相关信息。每个“可加载的” 或 “可分配的” 输出
section 通常包含两个地址:
通常 VMA 和 LMA 是相同的。在目标文件中, loadablle 或 allocatable 的输出
section 有两种地址: VMA 和 LMA。VMA 是执行输出文件时 section 所在的地址,而
LMA 是加载输出文件时 section 所在的地址。一般而言,某 section 的 VMA == LMA。
但在嵌入式系统中,经常存在加载地址和执行地址不同的情况:
符号 (Symobl): 每个目标文件都有符号表 (SYMBOL TABLE),包含已定义的符号 (对
应全局变量和 static 变量和定义的函数名字) 和未定义符号 (未定义的函数的名字和引
用但没定义的符号) 信息。
符号值: 每个符号对应一个地址。即符号指 (这与 C 程序内变量的值不一样,某种
情况下可以堪称变量地址) 可以使用 nm 命令查看
链接脚本最小实践
链接脚本赋值语句
表达式的语法和 C 语言的表达式语法一样,表达式的值都是整形,如果 ld 的运行主机
和生成文件的目标机都是 32 位,则表达式是 32 位数据,否则是 64 位数据。能够在表
达式内使用的值,设置符号的值。表达式格式如下:
除第一类表达式外,使用其他表达式需要 SYMBOL 被定义与目标文件。
. 是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间某位置 (或
某 section 内的偏移,如果它在 SECTIONS 命令内的某 section 描述内),该符号只能
在 SECTIONS 命令内使用。
注意:赋值语句包含 4 个语法元素:符号名,操作符,表达式,分号,
一个也不能少。被赋值后,符号所属的 section 被设置为表达式 EXPRESSION 所属的
SECTION。赋值语句可以出现在链接脚本的三个地方:
一个简单的例子
操作符优先级
(1) 表示前缀符 (2) 表示后缀符
表达式计算
链接器延迟计算大部分表示计算,但是对待与连接过程紧密相关的表达式,链接器会立即
计算表达式。如果不能计算就报错。比如,对于 section 的 VMA 地址,内核区域块的开
始地址和大小,与其相关的表达式应该立即被计算。
一个简单的例子
这个例子中,9+DEMO_ADDR 表达式的值用于设置 DemoText section 的 VMA 地址,因此
需要立即运算,但是由于 DEMO_ADDR 变量的值不确定,所以此时链接器无法确立表达式
的值,因此链接器会报错。
相对值和绝对值
在输出 section 描述符内的表达式,链接器取其相对值,相对于该 section 的开始位置
的偏移。在 SECTIONS 命令内且非输入 section 描述内的表达式,链接器去其绝对值。
通过 ABSOLUTE 关键字转换成绝对值,即在原来值的基础上加上表达式所的 section 的
VMA 值。
一个简单例子
这个例子中, _edata 符号的值是 .data section 的末尾值(绝对值,在程序地址空间
内)
链接脚本相关的内建函数:
具体实践请看:
链接脚本语法
ABSOLUTE
ADDR
ALIGN
ASSERT
AT
BLOCK
BYTE
COMMONPAGESIZE
CONSTANT
CREATE_OBJECT_SYMBOLS
DATA_SEGMENT_ALIGN
DATA_SEGMENT_END
DATA_SEGMENT_RELRO_END
DEFINED
DISCARD
ENTRY
EXCLUDE_FILE
EXTERN
FILL
GROUP
HIDDEN
INCLUDE
INPUT
KEEP
LOADADDR
LONG
MAX
MAXPAGESIZE
MEMORY
MIN
NEXT
NOCROSSREFS
ONLY_IF_RO
ONLY_IF_RW
OUTPUT
OUTPUT_ARCH
OUTPUT_FORMAT
OUTPUT_FORMAT(3)
OVERLAY
PHDRS
PROVIDE
PROVIDE_HIDDEN
QUAD
SEARCH_DIR
SECTIONS
SENGMENT_START
SHORT
SIZEOF(SECTION)
SIZEOF_HEADERS
SORT
SORT_NONE
SQUAD
STARTUP
TARGET
附录
linux 中链接脚本 ld 文件详解
LD scripts
LD scripts China
LD Usermanual
BiscuitOS Home
BiscuitOS Blog
Linux Kernel
Bootlin: Elixir Cross Referencer
赞赏一下吧 🙂