


该笔记是在看该书时的一些记录
zhy@desktop:~/doublemint/test$ ll SimpleSection.o
-rw-r--r-- 1 zhy zhy 1100 2011-07-06 20:32 SimpleSection.o
使用objdump可以查看ELF文件的各个段的信息
-h就是把ELF文件的各个段的基本信息打印出来(-x可以打印更多的信息)
zhy@desktop:~/doublemint/test$ 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 00000008 00000000 00000000 00000090 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 00000098 2**2
ALLOC
3 .rodata 00000004 00000000 00000000 00000098 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 00000025 00000000 00000000 0000009c 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 000000c1 2**0
CONTENTS, READONLY
也可以用size直接查看ELF文件的代码段、数据段和BSS段的长度( dec表示3个段长度的和的十进制,hex表示长度和的16进制)
zhy@desktop:~/doublemint/test$ size SimpleSection.o
text data bss dec hex filename
95 8 4 107 6b SimpleSection.o
不知道这里的text的size为什么是95,0x5b十进制大小应该是91才对阿
zhy@desktop:~/doublemint/test$ objdump -s -d SimpleSection.o
SimpleSection.o: file format elf32-i386
Contents of section .text:
0000 5589e583 ec088b45 08894424 04c70424 U......E..D$...$
0010 00000000 e8fcffff ffc9c38d 4c240483 ............L$..
0020 e4f0ff71 fc5589e5 5183ec14 c745f801 ...q.U..Q....E..
0030 0000008b 15040000 00a10000 00008d04 ................
0040 020345f8 0345f489 0424e8fc ffffff8b ..E..E...$......
0050 45f883c4 14595d8d 61fcc3 E....Y].a..
Contents of section .data:
0000 56000000 55000000 V...U...
Contents of section .rodata:
0000 25640a00 %d..
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520342e .GCC: (Ubuntu 4.
0010 332e342d 31307562 756e7475 31292034 3.4-10ubuntu1) 4
0020 2e332e34 00 .3.4.
Disassembly of section .text:
00000000 <func1>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 08 sub $0x8,%esp
6: 8b 45 08 mov 0x8(%ebp),%eax
9: 89 44 24 04 mov %eax,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 ret
0000001b <main>:
1b: 8d 4c 24 04 lea 0x4(%esp),%ecx
1f: 83 e4 f0 and $0xfffffff0,%esp
22: ff 71 fc pushl -0x4(%ecx)
25: 55 push %ebp
26: 89 e5 mov %esp,%ebp
28: 51 push %ecx
29: 83 ec 14 sub $0x14,%esp
2c: c7 45 f8 01 00 00 00 movl $0x1,-0x8(%ebp)
33: 8b 15 04 00 00 00 mov 0x4,%edx
39: a1 00 00 00 00 mov 0x0,%eax
3e: 8d 04 02 lea (%edx,%eax,1),%eax
41: 03 45 f8 add -0x8(%ebp),%eax
44: 03 45 f4 add -0xc(%ebp),%eax
47: 89 04 24 mov %eax,(%esp)
4a: e8 fc ff ff ff call 4b <main+0x30>
4f: 8b 45 f8 mov -0x8(%ebp),%eax
52: 83 c4 14 add $0x14,%esp
55: 59 pop %ecx
56: 5d pop %ebp
57: 8d 61 fc lea -0x4(%ecx),%esp
5a: c3 ret
可以看到.text段里所包含的正式SimpleSection.c里两个函数func1()和main()的命令。
先说明下,一个十六进制位表示4个二进制位,1个字节为8位,因此,0x55表示一个字节。
.text段的第一个字节"0x55"就是"func1()"函数的第一条"push %ebp"指令,而最后一个字节0xc3正式main()函数的最后一条指令"ret",字节数为91个,即0x5b字节,与前面得到的结果一致。(size结果为95,有待查找)
数据段和只读数据段
.data段保存的是那些已经初始化了的全局静态变量和局部静态变量(值不为0,否则放入.bss段)。SimpleSection.c代码里面一共有两个这样的变量,分别是global_init_varabal与static_var。
这两个变量每个4个字节,一共刚好8个字节,所以".data"段大小为8各字节,对应的十进制大小也即是程序里的变量大小。为什么存放的次序为-x54,0x00,0x00,0x00而不是0x00,0x00,0x00,0x54?这涉及CPU的字节序(Byte Order)的问题,也就是所谓的大端(Big-endian)和小端(Little-endian)的问题。
SimpleSection.c里面我们在调用"printf"的时候,用到了一个字符串常量"%d\n",它是一种只读的数据,所以它被放到了".rodata"段。
%的utf-8编码为0x25
d的utf-8编码为0x64
\n,即LINE FEED(LF) or new line(NL),end of line(EOL)的utf-8编码为0x0a
以\0结尾。
utf-8在这些字符上与ASCII相同,rodata段的4各字节刚好是这个字符串常量的ASCII字节序,最后以\0结尾。
.bss段存放的是未初始化的全局变量和局部静态变量,如上述代码中的global_uninit_var,static_var2就是被存放在.bss段,其实更准确的说法是.bss段为他们预留了空间。
但我们可以看到该段大小只有4个字节,这与global_uninit_var和static_var2的大小的8个字节不符合。
先看下SYMBOL TABLE:
SYMBOL TABLE:
00000000 l df *ABS* 00000000 SimpleSection.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .rodata 00000000 .rodata
00000000 l O .bss 00000004 static_var2.1202
00000004 l O .data 00000004 static_var.1201
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
00000000 g O .data 00000004 global_init_var
00000000 g F .text 0000001b func1
00000000 *UND* 00000000 printf
0000001b g F .text 00000040 main
00000004 O *COM* 00000004 global_uninit_var
只有static_var2被存放在了.bss段,而global_uninit_var却没有被存放在任何段,只是一个未定义的*COM*。
小的测试
static int x1 = 0;
static int x2 = 1;
x1,x2分别存放在什么段呢?
x1.bss,x2.data
其他段
1 .rodata1
Read only Data,这种段里存放的是只读数据,比如字符串常量、全局const变量。跟“.rodata”一样
2 .comment
存放的是编译器版本信息
Contents of section .comment:
0000 00474343 3a202855 62756e74 7520342e .GCC: (Ubuntu 4.
0010 332e342d 31307562 756e7475 31292034 3.4-10ubuntu1) 4
0020 2e332e34 00 .3.4.
例如474343对应的ASCII码值即为GCC
3 .debug
调试信息
4 .dynamic
动态链接信息
5 .hash
符号哈希表
6 .line
调试时的行号表,即源代码行号与编译后指令的对应表
7 .note
额外的编译器信息.比如程序的公司名\发布版本号等
8 .strtab
String Table.字符串表,用于存储ELF文件中用到的各种字符串
9 .symtab
Symbol Table.符号表
10 .shstrtab
Section String Table.段名表
11 .plt .got
动态链接的跳转表和全局入口表
12 .init .fini
程序初始化与终结代码段
扩展:
1.将一个图片转为一个object文件
$ objcopy -I binary -O elf32-i386 -B i386 image.jpg image.o
image.jpg为源图片,执行该语句后当前文件夹下会生成image.o
可是怎么应用呢??????没想清楚......有待查找
2.自定义段
我们在全局变量或函数之前加上"__attribute__((section("name")))"属性就可以把相应的变量或函数放到以"name"作为段名的段中。
例如程序里我添加了这么一句
__attribute__((section("FOO"))) int global = 42;
重新生成.o文件后查看
zhy@desktop:~/doublemint/factory$ 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 00000008 00000000 00000000 00000090 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 00000000 00000000 00000098 2**2
ALLOC
3 FOO 00000004 00000000 00000000 00000098 2**2
CONTENTS, ALLOC, LOAD, DATA
4 .rodata 00000004 00000000 00000000 0000009c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .comment 00000025 00000000 00000000 000000a0 2**0
CONTENTS, READONLY
6 .note.GNU-stack 00000000 00000000 00000000 000000c5 2**0
CONTENTS, READONLY
可见多了一个FOO段
注意该属性需要应用在全局变量上,如果是局部的,编译时会提示
zhy@desktop:~/doublemint/factory$ gcc -c SimpleSection.c
SimpleSection.c: In function ‘main’:
SimpleSection.c:25: error: section attribute cannot be specified for local variables