【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
链接脚本初探
链接器把各个模块(.o/.a/.so)之间相互引用的部分处理好, 使得各个模块(.o/.a/.so)之间能够正常地衔接, 最终生成可执行程序.
而链接脚本用于指导链接器的行为, 使得可以正确地处理目标文件和库文件之间的关系.
1. 链接脚本的作用:
- 合并各个目标文件中的段(*.data *.text *.bss …)
- 重定位各个段的起始地址(在*.o中指定的是相对地址, 绝对地址即运行时被放置的地址, 将会在链接器中被指定).
- 重定位各个标识符的最终地址(标识符 = 全局变量…, 即链接脚本中可以直接定义标识符并指定存储地址, 也可以直接指定源代码中标识符的存储地址)
2. 举个例子:
2.1 C源码(file.c):
#include<stdio.h>
static int global = 999;
void func(void)
{
printf("hello\n");
}
int main(void)
{
func();
return 0;
}
2.2 链接脚本(test.lds):
SECTIONS
{
.text 0x2000000:
{
*(.text)
}
.data 0x3000000:
{
*(.data)
}
.bss :
{
*(.bss)
}
}
2.3 编译指令:
$gcc file.c -o test test.lds
2.4 结果:
$objdump -h file
file: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
13 .text 000001a2 0000000002000000 0000000002000000 00200000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
22 .data 00000010 0000000003000000 0000000003000000 00400000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .bss 00000008 0000000003000010 0000000003000010 00400010 2**0
ALLOC
3. 需要注意的地方:
在链接脚本中, 各个段的链接地址必须符合自身平台的规范, 例如我上面的.text代码段的地址为.text 0x2000000, 在你的平台可能没办法使用(会报段错误), 你需要找到自身平台所允许的地址, 请巧用objdump命令:
# 找一个可以运行的应用, dump出它的链接地址, 抄到我们的链接脚本中即可.
$objdump xxxx
4. 小尾巴:
在上面的链接脚本中, 我们只使用了SECTIONS命令, 用于指定可执行程序中段的放置位置, 除此之外, 链接脚本还有MEMORY命令和ENTRY命令:
MEMORY命令对存储区域进行重定义, 而ENTRY命令指定可执行程序的入口地址.