一,二进制文件的类型
Linux下的二进制文件是ELF格式的,主要有目标文件、静态链接库文件、动态链接库文件、可执行文件和core dump文件。可以使用如下命令查看其类型:
file 文件名。
我们还是以之前的例子test.c举例,test.c的源代码和之前的文章一样:
int sub(int a,int b,int c){
*(int *)a=16;
return 0;
}
int main()
{
int a=0;
int b=1;
int c=2;
sub(a,b,c);
return 0;
}
a)使用gcc生成目标文件: gcc -c -o test.obj test.c
使用file查看:
file test.obj
test.obj: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
b)使用gcc 和ar生成静态库文件:
gcc -c -o test.o test.c
ar rcs libtest.a test.o
使用file查看:
file libtest.a
libtest.a: current ar archive
c)使用gcc生成动态链接库文件:
gcc -fPIC -c -o test.o test.c
gcc -shared -o libtest.so test.o
使用file查看:
file libtest.so
libtest.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
d)使用gcc生成可执行文件
gcc -o test test.c
使用file查看:
file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), for GNU/Linux 2.6.4, dynamically linked (uses shared libs), not stripped
e)运行产生core dump
./test
使用file查看:
file test-29728.core
test-29728.core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './test'
二,查看二进制文件段的信息
为了能够在查看二进制文件的同时,看到二进制文件中段的意义,采用的源代码如下所示:
*Linux:
gcc -c SimpleSection.c
*
*Windows:
* cl SimpleSection.c /c/Za
*/
int printf(const char*format,...);
int global_init_var=84;
int global_uninit_var;
static int global_static_var;
static int global_static_var1=1;
static int global_static_var0=0;
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;
}
使用gcc 编译出目标文件: gcc -c -o SimpleObject.o SimpleObject.c
使用binutils工具包中的objdump查看该二进制文件,-h表示查看段头:
objdump -h SimpleSection.o
SimpleSection.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000005b 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 0000000c 00000000 00000000 00000090 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 0000000c 00000000 00000000 0000009c 2**2
ALLOC
3 .rodata 00000004 00000000 00000000 0000009c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000002e 00000000 00000000 000000a0 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 000000ce 2**0
CONTENTS, READONLY
注解:
VMA即 Virtual Memory Address,即虚拟地址
LMA即 Load Memory Address即加载地址
正常情况下这两个地址一样,有些嵌入式系统这两个值不同。
.text是代码段,其大小为5b,在文件中的偏移是34
.data是数据段,大小是0c,在文件中的偏移是90
.bss是BSS段,大小是0c,文件中的偏移是9c
.bss是存储未初始化的全局变量和静态局部变量。其实仅仅是给这些变量预留空间。此处便是:
static int global_static_var;static int global_static_var0=0;static int static_var2,共12字节。由于static int global_static_var0=0相当于没有初始化(没有初始化的值就是0),因而被编译器优化到了.bss,因为这样不占用磁盘空间。
int global_uninit_var则没有被放到任何段,而是作为未定义的COMMON符号。这个和不同语言、编译器实现有关,有的编译器放到.bss 段,有的仅仅是预留一个COMMON符号,在链接的时候再在.bss段分配预留空间。编译单元内部可见的静态变量,比如在上述中加上static的 static int global_static_var则确实被放到了.bss,是因为这个仅仅是编译单元内部可见。
.rodata是只读数据段,大小是4,文件中偏移是9c。单独设立.rodata段,不仅仅直接在语义上支持了c++的const关键字,而且操作系统 加载的时候,可将其映射会只读,防止对只读数据的修改。在嵌入式平台下,有些时候使用ROM进行存储。有的编译器把字符串常量防到.data,而不是放 到.rodata,例如MSVC编译器就在编译C++的时候把字符串常量放置到.data段。
.comment是注释信息段,大小是2e,文件中的偏移是a0
.note.GNU-stack是GNU栈提示段,大小事0,文件中的偏移是ce
其中的属性 CONTENTS表示在文件中存在内容,没有该属性则表示在文件中不存在内容
这样,其结构如图:
也可使用size命令查看各个段的大小、地址信息,-format表示使用的输出格式:
size --format=SysV SimpleSection.o
SimpleSection.o :
section size addr
.text 91 0
.data 12 0
.bss 12 0
.rodata 4 0
.comment 46 0
.note.GNU-stack 0 0
Total 165
三,查看段的内容
使用 objdump的-s查看任何需要的段的内容,如果不指定段,则显示所有的非空段的内容,-d表示将代码段反汇编(disassemble)。
Contents of section .text:
0000 5589e583 ec088b45 08894424 04c70424 U......E..D$...$
0010 00000000 e8fcffff ffc9c38d 4c240483 ............L$..
0020 e4f0ff71 fc5589e5 5183ec14 c745f401 ...q.U..Q....E..
0030 0000008b 15080000 00a10400 00008d04 ................
0040 020345f4 0345f889 0424e8fc ffffff8b ..E..E...$......
0050 45f483c4 14595d8d 61fcc3 E....Y].a..
Contents of section .data:
0000 54000000 01000000 55000000 T.......U...
Contents of section .rodata:
0000 25640a00 %d..
Contents of section .comment:
0000 00474343 3a202847 4e552920 342e312e .GCC: (GNU) 4.1.
0010 32203230 30383037 30342028 52656420 2 20080704 (Red
0020 48617420 342e312e 322d3434 2900 Hat 4.1.2-44).
Disassembly of section .text:
00000000 <func1>:
0: 55 push �p
1: 89 e5 mov %esp,�p
3: 83 ec 08 sub $0x8,%esp
6: 8b 45 08 mov 0x8(�p),�x
9: 89 44 24 04 mov �x,0x4(%esp)
d: c7 04 24 00 00 00 00 movl $0x0,(%esp)
14: e8 fc ff ff ff call 15 <func1+0x15>
19: c9 leave
1a: c3