.o/.obj 文件的组成格式

我们知道.c/.cpp文件通过:预处理->编译->汇编过程,最终形成了.o/.obj文件,我们称之为可重定位的二进制目标文件,那么它有什么样的格式呢?为什么还不能运行?

我们从一个例子入手,进行.o/.obj文件的剖析:

写一个test.c,如下图:


对我写的test.c在Linux平台上利用GCC进行编译:得到test.o文件:

利用file命令查看test.o文件的属性:

我们得到认证:test.o文件是一个可重定位的二进制文件。

有了目标文件test.o,而且在Linux版本上支持的目标文件是ELF格式。我们使用objdump工具来查看目标文件的构成:


从图中查看得出几点认证:

1、程序在编译过程中,内存不为其分配空间。因为VMA(虚拟内存地址)和DMA(加载内存地址)都是0;

2、.bss段节省了文件内存的空间。因为.bss段和下一个段的File off(文件偏移量)是一样的。

3、对于只读数变量(const修饰的变量和字符常量)也设立了独立的段,就如上面的.rodata。

   原因有三:a.在语义上支持了C++的const关键字。

                       b.操作系统在加载的时候将“.rodata”段的属性映射成只读,不能修改,保证了程序的安全性。

                       c.保证放在在某些嵌入式平台上的只读存储器(ROM)中的程序访问的正确性。


从图中查看提出几个问题:

1、.text段不是从0开始偏移,而从0x00000034偏移,0x34转换为十进制就是52个字节的大小是什么?

2、.bss段和下面的段的偏移量一样,也就是说在文件中.bss不存在,那我们怎么知道它存了哪些数据?存放到哪?

3、.bss 段的大小是(14)换算成十进制就是20个字节,也就是说只有5个变量。可是已初始化的或者初始化为0 的变量有6个,分别是gdata2,gdata3,gdata5,gdata6,data5,data6.那么剩下4个字节(一个变量)存到了哪里?


带着这几个问题继续来分析test.o文件:

通过readelf命令看详细的ELF文件:


图中只做了一些比较重要的标记,具体的详细看《程序员的自我修养》书中第三章。

读图:

1、我们发现ELF Header(ELF文件头)的大小刚好是52个字节,与我们看到的.text的偏移量吻合,也就是说test.o文件格中ELF Heade下面就是代码段。因此前面提到的第一个问题就解决了。

2、段表在文件中的偏移是240个字节(换算成十六进制是0xf0),而且每个段表描述符的大小是40各字节,分别有11个,计算40*11=440(字节),总结一下就是test.o文件中段表的大小和偏移量在文件头中记录;在文件本身中段表占440个字节,从0xf0开始偏移。

3、在这块说一下魔数的概念:很多类型的文件,我们平时都是根据后缀名来区分,事实上,操作系统是根据魔数来辨认的;如果不小心把文件的后缀名改掉之后,表面上看起来文件类型变了,但是操作系统在加载可执行文件时用魔数来判断,当魔数不正确时,会拒接加载。

通过上面的叙述,段表中的11个段表描述符是什么呢?它440个字节到底记录了什么?我们通过命令readelf来看段表信息:

读图:

1、可以看出段表在文件中就是从0xf0开始偏移。它描述了每个段的段名(Name)、长度(Size)、在文件的偏移量(Off)、读写权限(Flg【A:可读;x:可执 行;W:可写】)和其他属性。

2、发现段表中还保存.bss段的内容,这就不难理解我们刚开始提出的第二个问题,因为.bss段存放未初始化的或已初始化为0的数据,它们都是0,没有必要在文件中一一记录下来,所以没有.bss段;但是要知道它们是存在的,段表就做了这份工作。


通过段表的记录,能看到每段的大小和偏移量。整体上我们对test.o文件的格式基本上已经迎刃而解了。


可是对刚开始提出的第三个问题,还没有解决,其实这个涉及到C语言中的强类型和弱类型。对于全局的没有初始化的数据(在本例子中是gdata3),单个文件进行编译的时候,它们都是独立的,而且不涉及符号的重定位,并不能确定是不是还有更强的符号或者占用字节更大的数据。只有在链接的时候,进行符号重定位时,没有强类型时才用本文件下的变量。同样的道理,在本例子中gdata3就是一个弱符号,在编译后的test.o文件中它是单独保存的:如下图加以确认:



读图:发现与我们想的一样,gdata2,gdata5,gdata6,data5,data6.保存在.bss段,gdata3单独存放在*COM*块中。

三个基本问题已解决,现在通过偏移量和大小可以画出目标文件的文件格式:(对于其他未提及的段以后会做以补充)


再查看一下文件的大小:


文件大小与我们画的test.o文件大小吻合。
  • 11
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值