天天看点

Linux之链接脚本

1. 什么是链接脚本

    链接器主要有两个作用,一是将若干输入文件(.o文件)根据一定规则合并为一个输出文件(例如ELF格式的可执行文件);二是将符号与地址绑定。本文只关心它的第一个功能,即如何根据一定规则将一个或多个输入文件合并成输出文件。这里的“一定规则”是通过链接脚本描述的。链接器有一个编译到其二进制代码中的默认链接脚本(可以使用–verbose命令行显示缺省的链接器脚本的内容),大多数情况下使用它链接输入文件并生成目标文件。当然,我们也可以提供自定义的脚本以精确控制目标文件的格式,如同Linux内核做得那样,链接器“- T”参数用于指定自定义的脚本文件。

2.简单的链接脚本示例

链接脚本由一系列命令组成, 每个命令由一个关键字(一般在其后紧跟相关参数)或一条对符号的赋值语句组成. 命令由分号‘;’分隔开. 

假设你的程序只有代码段,初始化过的数据段,和未初始化过的数据段.这些会存在于‘.text’,‘data’,‘bss’段中. 

对于这个例子,假设代码应该被载入到地址0x1000处,而数据应该从0x8000000开始,如下是实现这个功能的脚本: 

SECTIONS 

.=0x1000; 

.text:{*(.text)} 

.=0x8000000; 

.data:{*(.data)} 

.bss:{*(.bss)} 

具体分析: 

关键字SECTIONS开始于这个配置.后面跟有一串放在花括号中的符号赋值和输出端描述的内容. 

第一行是对一个特殊的符号‘.’赋值,这是一个定位标识器.如果你没有以其他的方式制定输出段的地址,那地址值就会被设为定位标识器的现有值,即0x1000.           

第二行定义一个输出段,‘.text’.冒号‘:’是语法需要,现在可以被忽略.段后面的花括号中,应该列出所有应该放入这个输出段中的输入端的名字. '*’是通配符,匹配所有文件名.即将所有输入文件中的.text段都保存在此段中. 

余下的是.data和.bss段,同理,链接器会把所有.data段从地址0x8000000开始处放置. 

最后,定位标识器的值变为0x8000000加上所有.data段的地址.此时链接器把所有.bss放在此处开始的地址.

3.简单的链接脚本命令

设置入口点 

在运行一个程序时,第一个被执行到的指令成为‘入口点’.你可以使用‘ENTRY’链接脚本命令来设置入口点.参数是一个符号名,如下: 

ENTRY(SYMBOL) 

有很多不同的方法来设置入口点.链接器会通过按顺序尝试一下方法来设置入口点. 

1,‘-e’入口命令行选项 

2,链接脚本中的ENTRY(SYMBOL)命令 

3,如果定义了start,就使用start的值 

4,如果存在就使用‘.text’段的首地址 

5,地址‘0’

4.基本概念

bss段: 

BSS段(bsssegment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。BSS段属于静态内存分配。

data段: 

数据段(datasegment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

text段: 

代码段(codesegment/textsegment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。

rodata段: 

存放C中的字符串和#define定义的常量

heap堆: 

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

stack栈: 

是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

常量段: 

常量段一般包含编译器产生的数据(与只读段包含用户定义的只读数据不同)。比如说由一个语句a=2+3编译器把2+3编译就算出5,存成常量5在常量段中

text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载; 而bss段不在可执行文件中,由系统初始化。

一般情况下,一个程序本质上都是由 bss段、data段、text段三个组成的——本概念是当前的计算机程序设计中是很重要的一个基本概念。而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。

在采用段式内存管理的架构中(比如intel的80x86系统),bss段(Block Started by Symbol segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零(bss段属于静态内存分配,即程序一开始就将其清零了)。

继续阅读