今年来学习一下目标文件。那啥是目标文件呢?简单的说:目标文件就是经过编译和汇编,但没有经过没了链接的文件。看一段测试代码:
#include <stdio.h>
int a = 84;//已初始化的全局变量
int b;//未初始化的全局变量
void func(int i)
{
printf("%d\n",i);
}
int main()
{
static int c = 85;//已初始化的局部静态变量
static int d;//未初始化的局部静态变量
int e = 1;//已初始化的局部变量
int f;//未初始化局部变量
func(c+d+e+f);
return e;
}
笔者linux下该文件名为test.c,则直接执行gcc -c test.c 命令,生成test.o文件。再看:
[mapan@localhost mapam]$ objdump -h test.o
test.o: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000054 0000000000000000 0000000000000000 00000040 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000008 0000000000000000 0000000000000000 00000094 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 0000000000000000 0000000000000000 0000009c 2**2
ALLOC
3 .rodata 00000004 0000000000000000 0000000000000000 0000009c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000002e 0000000000000000 0000000000000000 000000a0 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000ce 2**0
CONTENTS, READONLY
6 .eh_frame 00000058 0000000000000000 0000000000000000 000000d0 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
objdump -h 把ELF文件的各个段的基本信息打印出来。
竖着看:
.text为代码段,存放程序源代码编译后的机器指令。
.data为数据段,存放已初始化的全局变量和局部静态变量
.bss为数据段, 存放未初始化的全局变量和局部静态变量
.rodata为只读数据段
.conment为注释信息段
.note.GUN-stack为堆栈段
.eh_frame为调试信息段
横着看:
size为段的长度
File off 为段所在的位置
为了详细了解每个段的内容,我们需要查看反汇编。
[mapan@localhost mapam]$ objdump -s -d test.o
test.o: file format elf64-x86-64
Contents of section .text:
0000 554889e5 4883ec10 897dfcb8 00000000 UH..H....}......
0010 8b55fc89 d64889c7 b8000000 00e80000 .U...H..........
0020 0000c9c3 554889e5 4883ec10 c745f801 ....UH..H....E..
0030 0000008b 15000000 008b0500 0000008d ................
0040 04020345 f80345fc 89c7e800 0000008b ...E..E.........
0050 45f8c9c3 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 342e342e .GCC: (GNU) 4.4.
0010 37203230 31323033 31332028 52656420 7 20120313 (Red
0020 48617420 342e342e 372d3138 2900 Hat 4.4.7-18).
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001 .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000 ................
0020 00000000 24000000 00410e10 8602430d ....$....A....C.
0030 065f0c07 08000000 1c000000 3c000000 ._..........<...
0040 00000000 30000000 00410e10 8602430d ....0....A....C.
0050 066b0c07 08000000 .k......
Disassembly of section .text:
0000000000000000 <func>:
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: b8 00 00 00 00 mov $0x0,%eax
10: 8b 55 fc mov -0x4(%rbp),%edx
13: 89 d6 mov %edx,%esi
15: 48 89 c7 mov %rax,%rdi
18: b8 00 00 00 00 mov $0x0,%eax
1d: e8 00 00 00 00 callq 22 <func+0x22>
22: c9 leaveq
23: c3 retq
0000000000000024 <main>:
24: 55 push %rbp
25: 48 89 e5 mov %rsp,%rbp
28: 48 83 ec 10 sub $0x10,%rsp
2c: c7 45 f8 01 00 00 00 movl $0x1,-0x8(%rbp)
33: 8b 15 00 00 00 00 mov 0x0(%rip),%edx # 39 <main+0x15>
39: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 3f <main+0x1b>
3f: 8d 04 02 lea (%rdx,%rax,1),%eax
42: 03 45 f8 add -0x8(%rbp),%eax
45: 03 45 fc add -0x4(%rbp),%eax
48: 89 c7 mov %eax,%edi
4a: e8 00 00 00 00 callq 4f <main+0x2b>
4f: 8b 45 f8 mov -0x8(%rbp),%eax
52: c9 leaveq
53: c3 retq
objdump的-s参数可以将所有段的内容可以将所有段的内容以十六进制的方式打印出来,-d参数可以将指令的段反汇编。
对于Contents of section .text:最左面一列是偏移量,中间4列是十六进制内容,最右面一列是.text段的ASCII码形式。它是对.text的说明。
对于Contents of section .data:里面有2个值,54000000和55000000他们分别是示例代码中变量a和变量c。
对于.bss:
2 .bss 00000004 0000000000000000 0000000000000000 0000009c 2**2
它的大小是4,它存放代码示例中变量d,而变量b没有存放在.bss段,这是根编译器的实现有关。这里的变量b存放在.comment段,但是编译单元内部可见的静态变量是存放在.bss段的。
参考资料:程序员的自我修养