美文网首页
程序编译链接(二)-- 目标文件

程序编译链接(二)-- 目标文件

作者: wayyyy | 来源:发表于2018-10-02 18:20 被阅读0次

编译器编译源代码后生成的文件叫做目标文件。从结构上讲,它已经是编译后的可执行文件格式,只是还没有经过链接的过程,其中可能有些符号或有些地址还没有被调整。其本身是按照可执行文件格式存储的。

现在PC上流行的可执行文件格式,主要是Windows下的PE和Linux的ELF。
动态链接库(Windows的.dll和Linux的.so)和静态链接库(Windows的.lib和Linux的.a)文件也按照可执行文件格式存储。

目标文件格式

/* test.c */
int printf(const char* format, ...);

int global_init_var = 84;
int global_uninit_var;

void func1(int i)
{
    printf("%d\n", i);
}

int main()
{
    static int static_var = 85;
    static int static_var2;

    int a = 1;
    int b;

    func1(static_var + static_var2 + a + b);
    return a;
}

一般C语言编译后执行语句都编译成机器代码,保存在.txt段。
已初始化的全局变量和局部静态变量都保存在.data段。
未初始化的全局变量和局部静态变量一般放在.bss段。

进程映像.png
比如上面的global_init_varstatic_var.data段,global_uninit_varstatic_var2bss段。

总的来说,程序源代码被编译后主要分成两种段:程序指令程序数据,代码段属于程序指令,而数据段和.bss段属于程序数据。
也许会问:为什么要把程序的指令和数据分开?主要因为:

  • 一方面当程序被装载后,数据和指令分别被映射到两个虚存区域,由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个区域的权限可以被分别设置成可读写和只读,这样可以防止程序的指令被有意或无意地改写。

  • 另一方面是对于现代CPU来说,它们有着极为强大的缓存体系。指令区和数据区的分离有利于提高程序的局部性,现代CPU的缓存一般都被设计成数据缓存和指令缓存分离。

  • 当系统中运行着多个程序的副本时,它们的指令都是一样的,所以内存中只需要保存一份改程序的指令部分。对于程序的指令如此,其他只读数据也类似,比如:

$ gcc -m32 -c test.c -o test.o    # 
$ objdump -h test.o    # -h 把ELF文件的各个段的基本信息打印出来

objdump可用来查看各目标文件的结构和内容。参数-h表示把ELF文件的各个段的基本信息打印出来。

段信息.png

代码段

$ objdump -d test.o

-d将包含指令的段反汇编。


数据段和只读数据段

  • .data
    .data段保存是初始化了得全局变量,静态变量和局部静态变量,前面有2个这样的变量是global_init_var = 84 = 0x00000054static_var = 85 = 0x00000055,一共8字节。(x86 的是小端序,高位存放在高地址中)

    .data段.png
  • .rodata只读数据段
    保存的是只读数据,一般是程序的只读变量(如const修饰的变量)和字符串常量。比如上面我们用到了字符串常量 %d\n,它是一种只读数据。"25640a00"也恰好是这个字符串常量的ASCII字节序。

    .rodata段.png

.bss

.bss段存放的是未初始化的全局变量和局部静态变量。可以看到该段的大小只有4字节,但global_uninit_varstatic_var2的大小应该是8字节。这不是矛盾了?
实际上,只有static_var2被存放到了被存放到了.bss段,而global_uninit_var却没有存放在任何段,只是一个未定义的COMMON符号。这跟编译器实现有关,有些编译器会将全局的未初始化变量存放在目标文件的.bss段,有些则不存放,只是预留一个未定义的全局变量符号,等到最终链接成可执行文件的时候再在.bss段分配空间。

.comment

.comment段一般存放编译器版本信息

.comment段.png

其他段

自定义段

相关文章

  • 程序编译链接(二)-- 目标文件

    编译器编译源代码后生成的文件叫做目标文件。从结构上讲,它已经是编译后的可执行文件格式,只是还没有经过链接的过程,其...

  • C语言生成可执行文件的编译过程

    C语言源文件要经过编译、链接才能生成可执行程序: 1、 编译(Compile)会将源文件(.c文件)转换为目标文件...

  • 链接器简述

    本质: 链接器本质上也是一个程序:是将编译器产生的目标文件打包成可执行文件或者库文件或者目标文件的程序。 静态链接...

  • 5.静态链接和动态链接

    静态链接:在编译目标软件的同时将其他资源编译到该目标文件中,缺点,会占用较多的资源,空间。动态链接:目标程序在运行...

  • Linux 目标文件的格式

    编译器用于为源程序文件产生对应的二进制代码和数据目标文件。链接程序用于对相关的所有目标文件进行组合处理,形成一个可...

  • 计算机那些事(3)——ELF文件结构

    原文链接 前文结尾说到编译器编译源代码后生成的文件叫做目标文件,而目标文件经过编译器链接之后得到的就是可执行文件。...

  • 程序员的自我修养

    程序员的自我修养:编译、链接、装载 问题 编译/链接的过程做了什么 目标/可执行文件的内容是什么 装载的过程做了什...

  • 开发流程

    .m文件(源文件) 编译成 .o文件(目标文件) 链接 a.out文件(目标文件)

  • Xcode编译原理

    Xcode编译原理 1.xcode 编译的过程 源文件.c --> 编译 --> 目标文件.o --> 链接 --...

  • iOS 应用的构建过程

    一、应用构建过程 1.编译源文件:使用Clang编译项目中所有参与编译的源文件,生成目标文件。2.链接目标文件:将...

网友评论

      本文标题:程序编译链接(二)-- 目标文件

      本文链接:https://www.haomeiwen.com/subject/onqriftx.html