Linux链接①:目标文件格式

本文介绍链接器的工作原理,包括符号解析和重定位的过程,并详细解释了不同类型的链接方式及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:

将各种代码段和数据段收集组合成为一个单一文件的过程。

链接的执行过程可以发生在三种时期:

  • 编译期:源代码翻译成机器代码的过程中。
  • 加载期:程序被内核加载器加载到内存时。
  • 运行期:应用程序来控制执行。

链接器的出现使得构建大型软件系统成为可能,因为它使得各个模块可以单独完成编译。当需要改进模块时,单独的修改相应的模块并编译,通过链接器重新链接生成新版本的软件系统。

根据链接的发生时期不同分为以下三类:

  • 传统静态链接
  • 加载时共享库动态链接
  • 运行时共享库动态链接

一个典型的链接过程:

sum.cpp中定义一个函数
int sum(int a,int b)
{
    return a+b;
}
main.cpp中声明并使用
int sum(int,int);
int main()
{
    int a=1;
    int b=2;
    int c=sum(a,b);
}

 

编译系统通常包含预处理器、编译器、汇编器、链接器。通过这些不同部分完成程序从源代码到最终可执行程序的过程。

GNU编译系统对上述程序的过程为:

g++ main.cpp sum.cpp -o prog
  • main.cpp=>main.o
  • sum.cpp=>sum.o
  • ld链接器:sum.o+main.o=》完成链接的可执行程序prog

Linux LD链接器以一组可重定位的目标文件(.o)为输入,指定相应的参数,生成一个完全链接,可以加载和运行的可执行目标文件(即:可执行文件)。

链接器的主要任务为:

①符号解析:symbol resolution 目标文件中定义和引用符号。每个符号可能对应于一个函数、一个全局变量、或者一个静态变量(局部变量在运行时栈中创建) 符号解析就是将符号引用与符号定义关联起来。

②重定位:relocation 编译器和汇编器生成的地址是从0开始的逻辑地址。链接器通过把每个符号定义与内存中一个位置关联起来,从而重定位这些部分。具体做法是使用汇编器产生的重定位条目信息执行重定位。

 

目标文件存在三种类别:

  • 可重定位目标文件:包含二进制的代码和数据,可以在编译时与其它可重定位目标文件组合起来,生成可执行目标文件。
  • 可执行目标文件:包含二进制代码和数据,其形式可直接复制进内存执行
  • 共享目标文件:一种特殊的目标文件,可以在加载或者运行时被动态的加载进内存并链接。

 

【目标文件格式】

目标文件是对程序二进制代码和数据的组织,贝尔实验室第一个Unix系统使用a.out格式,windows使用可移植可执行的PE格式(如最常见的可执行程序.exe格式) 而Linux中使用的是ELF (executable and linkable format)格式。

ELF可重定位目标文件格式

 

ELF头:描述系统的字的大小以及字节顺序(大小端) 以及其它用于链接器语法分析和解释目标文件的信息。

目标文件通常包含以下这些节:

.text程序的机器代码
.rodataread only data 只读数据,如printf 中格式串
.data已经初始化的全局或静态变量(局部变量运行期创建在栈中)
.bss未初始化的全局或静态变量,不占据实际空间,仅仅为一个占位符
.symtab符号表:存放程序中定义和引用的函数和全局(静态)变量信息
.rel.text对应与.text中位置的列表,调用外部函数或者引用全局变量时修改
.rel.data被模块引用或者定义的所有全局变量的重定位信息

 

objdump -x add.o   linux中采取objdump才看ELF目标文件信息

 

可以看到目标文件中,主要包含代码段、数据段等节,同时以及最重要的符号表(symbol_tab)

自定义函数 add_funii  (已经被编译期重新修改函数名 典型的加上i  i  对应参数描述) 在符号表最后一个。

 

【符号与符号表】

符号表包含所在可重定位模块定义和引用的符号的信息,通常包含三种不同的符号:

类别对应于源程序
全局符号:由本模块定义,能被其它模块引用的符号对应于C++源代码中定义的全局变量和函数
局部符号:由本模块定义,但不能被其它模块引用的符号对应于C++源代码中定义的本文件可见的static 变量和函数
外部符号:由其它模块定义并被本模块引用的全局符号本文件声明使用,在其它源文件定义的全局变量和函数


注意:

符号表中不包含任何局部非静态变量的任何符号,这是因为这些局部变量都是在运行时栈中创建和销毁。

因此,static关键字最重要的用途:使得被修饰的函数或变量只能在本模块(文件)中可见。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值