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

2018-10-02  本文已影响0人  wayyyy

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

现在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段属于程序数据。
也许会问:为什么要把程序的指令和数据分开?主要因为:

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

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

段信息.png

代码段

$ objdump -d test.o

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


数据段和只读数据段

.bss

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

.comment

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

.comment段.png

其他段

自定义段

上一篇 下一篇

猜你喜欢

热点阅读