Linux链接①:目标文件格式

    科技2026-06-04  11

    链接:

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

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

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

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

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

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

    一个典型的链接过程:

    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.osum.cpp=>sum.old链接器: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关键字最重要的用途:使得被修饰的函数或变量只能在本模块(文件)中可见。

     

     

     

     

     

    Processed: 0.014, SQL: 9