【静态链接】第2章---------------------目标文件(它是什么)


########  该系列博文为书籍《程序员的自我修养》的笔记 ##########


【说明】

             我们知道,在windows下和在linux有一点是一样的,那就是我们的源代码都要编译,链接成可执行文件,而在链接之前,我们需要把各个源代码编译成目标文件,在linux下是.o后缀,显然这些目标文件是有格式的,而不是单单包含着指令和数据。这一章就来介绍目标的格式,只有知道了格式,才能理解链接的过程。windows下可执行文件是PE格式的,而linux下是ELF格式的,他们有一定差别,却来至同一个祖先COFF。


【什么是目标文件】

              目标文件就是源代码编译后但未进行链接的那些中间文件,linux 下是.o文件  windows下是.obj文件。其实目标文件和最后的可执行文件格式是类似的,所以一般都采用一种格式。



【目标文件里有什么】

                先来看一张图,里面标记了一个简单的C语言,各个部分在对应的目标文件中的位置。

                

                  1)显然,我们看到目标文件开头有一个文件头,我们猜测里面有整个目标文件的信息。

                  2)初始化且非0的全局变量放在.data 段(后面section 我们都称为段)

                  3)未初始化和初始值为0的全局变量放在.bss 段

                  4)函数中的静态变量处理方法同全局变量

                  5)指令放.text 段

                 ※:为什么要分段呢:

                                     1)数据和指令有不同访问权限,分开好管理

                                     2)现在CPU指令寄存器和数据寄存器是分开的,两者分段,发挥局部定理的优势

                                     3)便于共享,比如指令,既然是只读的,如果大家都要用,内存里放一份就可以了



【探索.o文件】

                   将下面的例子编译成.o文件

                   

int printf(const char *format, ... );

int global_init_var = 84;
int global_uninit_var;

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

int main(void)
{
         static int static_var = 85;
         static int static_var2;
         int a = 1;
         int b;
        
         func1(static_var + static_var2 + a + b);
         return a;
}

                    执行objdump -h simp.o 如下

                   

                   1)这个命令是读取.o 文件的基本信息(而不是头文件信息)

                   2)我们看到,段比我们想象的要多,很多段我们都不认识,在后面就知道了。

                   3)我们先来关注其中的 Size  和  File off 属性,然后将他们整理得到如下的文件分布,其实.note.GNU-stack 先无视

                        



       

【展开.text】

                       我们一个一个看看这几个段中就放了什么东西,先来看看.text 里面应该放着所有的指令 

                       利用指令 objdump -s -d simp.o 可以得到目标文件的内容

                       

                      这个的.text 的内容,这样子看不出来,因为里面放的是机器码,还好这个命令比较聪明,加了-d会把输出反汇编 

                      

                     这个就是我们源代码中的指令部分反汇编后的结果了。。。(一部分)


【展开.data和.rodata】

                     其中 .rodata 是只读数据段,为什么它大小是4呢,其实是因为我们刚才的%d\n 字符串。。。。3 + 一个结束符 

                     还是刚才的命令中,可以找到这么一段

                    

                   瞧,,看到了吧 .rodata 中真的有个 %d 

                  其中的54000000  是十六进制的,由于机器是小端机所以真值应该为0x00000054  也就是 十进制84  刚好是gloval_init_var,后面的85是什么猜猜都知道了

 【.bss】

                  关于.bss 段,其实.bss段里并没有真正的给变量分配空间,在文件里.bss段其实只保存了大小,而不像.data段有具体的数值,为什么?因为.bss段里面数据全   是0啊,你既然知道全是0了 ,还放那么多0在那干什么,浪费空间吗,只要装入内存的时候,按大小在内存里清出那么大一片0区域不就行啦。反正运行的时候用   的是内存里的数据。



【其他段】

                除了这些常用的段,还有一些

                

                 1)用户是可以自己定义段名的,但是一般不要把自己的段用"."开头,不然容易和系统的冲突

                 2)自定义段名方法: 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值