【Linux】探索目标文件 (.obj \ .o) 的体系结构

说在前面

该篇文章以 SimpleSection.c 文件编译出来的目标文件 SimpleSection.o 为对象,我们一起来分析分析:目标文件中到底包含了什么东西?它的内容是如何分段的?

一、编写 SimpleSection.c 并编译成 SimpleSection.o

SimpleSection.c

int printf( const char* format, ... );
int global_init_var = 84;
int global_uninite_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文件编译成.o文件

[gongruiyang@localhost ws]$ gcc -c SimpleSection.c
[gongruiyang@localhost ws]$ ls
SimpleSection.c  SimpleSection.o
[gongruiyang@localhost ws]$ file SimpleSection.o
SimpleSection.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

我们发现 SimpleSection.o是一个Relocatable File(可重定位文件)

二、使用 objdump 工具查看目标文件的分段结构

由此我们可以看出:.o的目标文件的体系结构主要分为 6 部分,分别是 .text段.data段.bss段.rodate段(只读数据段).comment段(注释信息段).note.GNU-stack段(堆栈提示段).eh_frame段

Size 表示段的长度;FILE off 表示段所在的位置;其中CONTENTS表示段的属性,含义为该段是否在文件中存在

[gongruiyang@localhost ws]$ objdump -h SimpleSection.o
SimpleSection.o:     文件格式 elf64-x86-64
节:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000055  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  00000098  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000004  0000000000000000  0000000000000000  000000a0  2**2
                  ALLOC
  3 .rodata       00000004  0000000000000000  0000000000000000  000000a0  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .comment      0000002d  0000000000000000  0000000000000000  000000a4  2**0
                  CONTENTS, READONLY
  5 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000d1  2**0
                  CONTENTS, READONLY
  6 .eh_frame     00000058  0000000000000000  0000000000000000  000000d8  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

如图所示:

在这里插入图片描述

由于.note.GNU-stackSize 为 0,并且 .bss 没有CONTENTS,所以我们可以认为没有这两个段

所以该ELF文件实际存在的也就是五个段: .text段.data段.rodate段(只读数据段).comment段(注释信息段).eh_frame段

三、使用 objdump 工具查看目标文件分段具体内容

接下来,我们看一看每个段的具体内容

[gongruiyang@localhost ws]$ objdump -sd SimpleSection.o
SimpleSection.o:     文件格式 elf64-x86-64

Contents of section .text:
 0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...
 0010 bf000000 00b80000 0000e800 00000090  ................
 0020 c9c35548 89e54883 ec10c745 fc010000  ..UH..H....E....
 0030 008b1500 0000008b 05000000 0001c28b  ................
 0040 45fc01c2 8b45f801 d089c7e8 00000000  E....E..........
 0050 8b45fcc9 c3                          .E...  
 
Contents of section .data:
 0000 54000000 55000000                    T...U...     
 
Contents of section .rodata:
 0000 25640a00                             %d..      
 
Contents of section .comment:
 0000 00474343 3a202847 4e552920 372e332e  .GCC: (GNU) 7.3.
 0010 31203230 31383033 30332028 52656420  1 20180303 (Red 
 0020 48617420 372e332e 312d3529 00        Hat 7.3.1-5).   
 
Contents of section .eh_frame:
 0000 14000000 00000000 017a5200 01781001  .........zR..x..
 0010 1b0c0708 90010000 1c000000 1c000000  ................
 0020 00000000 22000000 00410e10 8602430d  ...."....A....C.
 0030 065d0c07 08000000 1c000000 3c000000  .]..........<...
 0040 00000000 33000000 00410e10 8602430d  ....3....A....C.
 0050 066e0c07 08000000                    .n......        

Disassembly of section .text:
0000000000000000 <func1>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 83 ec 10          	sub    $0x10,%rsp
   8:	89 7d fc             	mov    %edi,-0x4(%rbp)
   b:	8b 45 fc             	mov    -0x4(%rbp),%eax
   e:	89 c6                	mov    %eax,%esi
  10:	bf 00 00 00 00       	mov    $0x0,%edi
  15:	b8 00 00 00 00       	mov    $0x0,%eax
  1a:	e8 00 00 00 00       	callq  1f <func1+0x1f>
  1f:	90                   	nop
  20:	c9                   	leaveq 
  21:	c3                   	retq   
0000000000000022 <main>:
  22:	55                   	push   %rbp
  23:	48 89 e5             	mov    %rsp,%rbp
  26:	48 83 ec 10          	sub    $0x10,%rsp
  2a:	c7 45 fc 01 00 00 00 	movl   $0x1,-0x4(%rbp)
  31:	8b 15 00 00 00 00    	mov    0x0(%rip),%edx        # 37 <main+0x15>
  37:	8b 05 00 00 00 00    	mov    0x0(%rip),%eax        # 3d <main+0x1b>
  3d:	01 c2                	add    %eax,%edx
  3f:	8b 45 fc             	mov    -0x4(%rbp),%eax
  42:	01 c2                	add    %eax,%edx
  44:	8b 45 f8             	mov    -0x8(%rbp),%eax
  47:	01 d0                	add    %edx,%eax
  49:	89 c7                	mov    %eax,%edi
  4b:	e8 00 00 00 00       	callq  50 <main+0x2e>
  50:	8b 45 fc             	mov    -0x4(%rbp),%eax
  53:	c9                   	leaveq 
  54:	c3                   	retq   

1、text段

根据源代码翻译而成的汇编代码

[gongruiyang@localhost ws]$ objdump -sd SimpleSection.o
SimpleSection.o:     文件格式 elf64-x86-64

Contents of section .text:
 0000 554889e5 4883ec10 897dfc8b 45fc89c6  UH..H....}..E...
 0010 bf000000 00b80000 0000e800 00000090  ................
 0020 c9c35548 89e54883 ec10c745 fc010000  ..UH..H....E....
 0030 008b1500 0000008b 05000000 0001c28b  ................
 0040 45fc01c2 8b45f801 d089c7e8 00000000  E....E..........
 0050 8b45fcc9 c3                          .E...  
 
 ......
 
 Disassembly of section .text:
0000000000000000 <func1>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 83 ec 10          	sub    $0x10,%rsp
   8:	89 7d fc             	mov    %edi,-0x4(%rbp)
   b:	8b 45 fc             	mov    -0x4(%rbp),%eax
   e:	89 c6                	mov    %eax,%esi
  10:	bf 00 00 00 00       	mov    $0x0,%edi
  15:	b8 00 00 00 00       	mov    $0x0,%eax
  1a:	e8 00 00 00 00       	callq  1f <func1+0x1f>
  1f:	90                   	nop
  20:	c9                   	leaveq 
  21:	c3                   	retq   
0000000000000022 <main>:
  22:	55                   	push   %rbp
  23:	48 89 e5             	mov    %rsp,%rbp
  26:	48 83 ec 10          	sub    $0x10,%rsp
  2a:	c7 45 fc 01 00 00 00 	movl   $0x1,-0x4(%rbp)
  31:	8b 15 00 00 00 00    	mov    0x0(%rip),%edx        # 37 <main+0x15>
  37:	8b 05 00 00 00 00    	mov    0x0(%rip),%eax        # 3d <main+0x1b>
  3d:	01 c2                	add    %eax,%edx
  3f:	8b 45 fc             	mov    -0x4(%rbp),%eax
  42:	01 c2                	add    %eax,%edx
  44:	8b 45 f8             	mov    -0x8(%rbp),%eax
  47:	01 d0                	add    %edx,%eax
  49:	89 c7                	mov    %eax,%edi
  4b:	e8 00 00 00 00       	callq  50 <main+0x2e>
  50:	8b 45 fc             	mov    -0x4(%rbp),%eax
  53:	c9                   	leaveq 
  54:	c3                   	retq   

2、data段和rodata段

Contents of section .data:
 0000 54000000 55000000                    T...U...     
 
Contents of section .rodata:
 0000 25640a00                             %d..   

可以看出 .data 段保存了两个变量,共占 8 个字节:

初始化为84(0x54)的全局变量global_init_var

``初始化为85(0x55)的静态局部变量static_var`

由于在printf函数中,用到了一个字符串常量%d\n,所以它被放在了.rodata段

所以,.rodata段一般存放只读常量,例如const修饰的变量或者常量字符串

3、 bss段

我们代码中,一共有两个变量:未初始化的全局变量global_uninite_var未初始化的局部静态变量static_var2,按理来说应该分配至少8个字节的内存,但是bss段却只分配了4个字节,说明只有一个变量被存进了bss段,另外一个变量存在了其他地方!

原因:只有局部静态变量被存进了bss段中,而未初始化的全局变量没有被存放在任何一个段中,在符号表中能够看到这个全局变量只是一个未定义的 “COMMON 符号”

4、comment段

Contents of section .comment:
 0000 00474343 3a202847 4e552920 372e332e  .GCC: (GNU) 7.3.
 0010 31203230 31383033 30332028 52656420  1 20180303 (Red 
 0020 48617420 372e332e 312d3529 00        Hat 7.3.1-5).  

这个段保存了编译器的版本信息

[gongruiyang@localhost ws]$ gcc -v
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值