文章目录
说在前面
该篇文章以 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-stack
的Size
为 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)