这篇文章主要分析链接的过程,需要项目编译过程中都会涉及到链接的问题,链接脚本后缀lds。
一、基础部分
1、段说明
- text段
代码段,通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定。 - data段
数据段,通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。 - bss段
通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。BSS段属于静态内存分配。 - init段
linux定义的一种初始化过程中才会用到的段,一旦初始化完成,那么这些段所占用的内存会被释放掉,后续会继续说明
2、各种地址说明
- 地址解释
- 加载地址:程序中指令和变量等加载到RAM上的地址。
- 运行地址:CPU执行一条程序中指令时的执行地址,也就是PC寄存器中的值。更简单的讲,就是要寻址到一个指令或者变量所使用的地址。
- 链接地址:链接过程中链接器为指令和变量分配的地址。
- 地址之间联系
注意,运行地址并不一定完全和链接地址相同,也不一定完全和加载地址相同。- 如果没有打开MMU,并且使用的是位置相关设计,那么加载地址、运行地址、链接地址三者需要一致。
需要保证链接地址和加载地址是一致的,否则会导致程序跑飞,从uboot上可以理解。 - 当打开MMU之前,如果使用的是位置无关设计,那么运行地址和加载地址应该是一致的
例如kernel在打开mmu之前,使用的是位置无关设计,其运行地址和加载地址一致。关于位置无关设计请自行度娘。 - 如果打开了MMU,那么运行地址和链接地址相同。
硬件会根据运行地址进行计算并自动寻址到对应的加载地址上。
- 如果没有打开MMU,并且使用的是位置相关设计,那么加载地址、运行地址、链接地址三者需要一致。
- 举例说明
例如:- uboot(BL2)阶段并没有打开MMU,并且其使用的是位置相关设计,所以其加载地址和链接地址都需要设置成相同,也就是加载地址是0x23E00000,链接地址也是0x23E00000,运行地址也需要和这两者一致
- kernel启动过程中,在MMU打开之前,使用的是位置无关设计,
内核镜像加载地址是0x20008000,链接地址是0xc0008000,运行地址是0x20008000. - 打开MMU之后,
内核镜像加载地址是0x20008000,链接地址是0xc0008000,运行地址是0xc0008000.
二、链接脚本语言
给出一个简单的vmlinux.lds.S的例子:
SECTIONS
{
. = 0x10000;
.text : {
*(.text) }
. = 0x8000000;
.data : {
*(.data) }
.bss : {