可执行程序的变量存储到底有什么规律呢?
测试一下:
Windows x86 (vs2010)、 x64(gcc)
Linux ARM (gcc)
code:
unsigned long g_A = 0x11223344;
unsigned long g_B;
unsigned long function()
{
static unsigned long s_A = 0xAABBCCDD;
static unsigned long s_B;
unsigned long A = 0x55667788;
s_A ++;
s_B = s_A;
return A;
}
int main(int argc, char** argv)
{
unsigned long B = 0x99999999;
B = function();
return 0;
}
1、编译选项:Windows, x86
, 优化全关闭(vs2010)
Dump of file E:\users\blastts\documents\visual studio 2010\Projects\testSection\Release\testSection.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
5 number of sections
54D6CDF6 time date stamp Sun Feb 08 10:46:14 2015
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine
SECTION HEADER #1
.text name
82A virtual size
1000 virtual address (00401000 to 00401829)
A00 size of raw data
400 file pointer to raw data (00000400 to 00000DFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read
SECTION HEADER #2
.rdata name
5C6 virtual size
2000 virtual address (00402000 to 004025C5)
600 size of raw data
E00 file pointer to raw data (00000E00 to 000013FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only
SECTION HEADER #3
.data name
394 virtual size
3000 virtual address (00403000 to 00403393)
200 size of raw data
1400 file pointer to raw data (00001400 to 000015FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
Read Write
SECTION HEADER #4
.rsrc name
1B4 virtual size
4000 virtual address (00404000 to 004041B3)
200 size of raw data
1600 file pointer to raw data (00001600 to 000017FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only
SECTION HEADER #5
.reloc name
18E virtual size
5000 virtual address (00405000 to 0040518D)
200 size of raw data
1800 file pointer to raw data (00001800 to 000019FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
Read Only
Summary
1000 .data
1000 .rdata
1000 .reloc
1000 .rsrc
1000 .text
不出意外的话,全局变量unsigned long g_A = 0x11223344;,静态变量static unsigned long s_A = 0xAABBCCDD;应该都是存在一起的。
SECTION HEADER #3
.data name
RAW DATA #3
00403000: 44 33 22 11 DD CC BB AA
而局部变量则又是在一起的
SECTION HEADER #1
.text name
RAW DATA #1
00401000: 55 8B EC 51 C7 45 FC **88 77 66 55** A1 04 30 40 00 U.имQ?Eи╣.wfU?.0@.
00401010: 83 C0 01 A3 04 30 40 00 8B 0D 04 30 40 00 89 0D .ид.бъ.0@....0@...
00401020: 24 30 40 00 8B 45 FC 8B E5 5D C3 CC CC CC CC CC $0@..Eи╣.?]?имимимимим
00401030: 55 8B EC 51 C7 45 FC **99 99 99 99**
既然.text是Execute Read,那么必然有:
01021030 testSection!main (int, char **)
0:000> u testSection!main
testSection!main [e:\users\blastts\documents\visual studio 2010\projects\testsection\testsection\testsection.cpp @ 20]:
01021030 55 push ebp
01021031 8bec mov ebp,esp
01021033 51 push ecx
01021034 c745fc99999999 mov dword ptr [ebp-4],99999999h
0102103b e8c0ffffff call testSection!function (01021000)
01021040 8945fc mov dword ptr [ebp-4],eax
01021043 33c0 xor eax,eax
01021045 8be5 mov esp,ebp
而没初值的s_B,(忘记关ASLR了,很容易就能算出RAW,所以先不管它)
0102101e 890d24300201 mov dword ptr [testSection!s_B (01023024)],ecx
0:000> !dh 0x1020000
OPTIONAL HEADER VALUES
10B magic #
10.00 linker version
A00 size of code
C00 size of initialized data
0 size of uninitialized data
12D7 address of entry point
1000 base of code
----- new -----
**01020000 image base**
SECTION HEADER #3
.data name
394 virtual size
3000 virtual address
200 size of raw data
1400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
(no align specified)
Read Write
可见是位于.data中的。因为vs生成的这东西没有.bss,所以不完全
像是他们所说,至少vs编译的c++程序,未初始化的全局变量不一定在.bss中。不过其实多个.bss也还不错,可能是没开优化的缘故?
其它的倒是很符合。全局变量在.data,局部变量跟着代码一起在.text中。
2、编译选项:Windows, x64
, 优化全关闭(gcc 4.1)
跟vs的大同小异,只不过gcc生成的节是真的很多,挑一些重点发。
首先,全局变量,静态变量,跟之前一样。
SECTION HEADER #2
.data name
100 virtual size
8000 virtual address (0000000000408000 to 00000000004080FF)
200 size of raw data
6E00 file pointer to raw data (00006E00 to 00006FFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0500040 flags
Initialized Data
RESERVED - UNKNOWN
RESERVED - UNKNOWN
Read Write
RAW DATA #2
0000000000408000: 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000000000408010: 44 33 22 11 DD CC BB AA
局部变量、函数也是一样
SECTION HEADER #1
.text name
67D0 virtual size
1000 virtual address (0000000000401000 to 00000000004077CF)
6800 size of raw data
600 file pointer to raw data (00000600 to 00006DFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60500020 flags
Code
RESERVED - UNKNOWN
RESERVED - UNKNOWN
Execute Read
RAW DATA #1
0000000000401500: 55 48 89 E5 48 83 EC 10 C7 45 FC 88 77 66 55
剩余的,我看到了bss的存在!
SECTION HEADER #6
.bss name
1400 virtual size
D000 virtual address (000000000040C000 to 000000000040D3FF)
0 size of raw data
0 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0600080 flags
Uninitialized Data
RESERVED - UNKNOWN
RESERVED - UNKNOWN
Read Write
先看看使用这个之前没初始化过的变量的地方:
0:002> u image00000000_00400000+0x1533
image00000000_00400000+0x1533:
00000000`00401533 8b05db7a0000 mov eax,dword ptr [image00000000_00400000+0x9014 (00000000`00409014)]
00000000`00401539 83c001 add eax,1
00000000`0040153c 8905d27a0000 mov dword ptr [image00000000_00400000+0x9014 (00000000`00409014)],eax
00000000`00401542 8b05cc7a0000 mov eax,dword ptr [image00000000_00400000+0x9014 (00000000`00409014)]
00000000`00401548 8905f6ba0000 mov dword ptr [image00000000_00400000+0xd044 (00000000`0040d044)],eax
这个倒是很符合:
static unsigned long s_B;
0:002> ?[poi[image00000000_00400000+0xd044]]
Evaluate expression: 0 = 00000000`00000000
static unsigned long s_A = 0xAABBCCDD;
0:002> ?[poi[image00000000_00400000+0x9014]]
Evaluate expression: 2864434397 = 00000000`aabbccdd
看吧,文件中预留的是0字节,只在启动后才从这里初始化一片0内存给它用,本意是减少(……节的描述都不止4字节了,浪费了更多,其实我觉得VS这里的做法反而是对的)文件大小,但是实际上如果没初始化的全局变量或者静态变量本身就不多的话,我觉得还不如并到.data节呢。
3、Linux (ARM) ,编译器GCC,无优化。
pi@BLASTN2 ~/projects/testSection/testSections/bin/Release :( $ objdump -h testSections
testSections: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000019 00008134 00008134 00000134 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 00008150 00008150 00000150 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 00008170 00008170 00000170 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .hash 00000028 00008194 00008194 00000194 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 00000024 000081bc 000081bc 000001bc 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 00000050 000081e0 000081e0 000001e0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 00000077 00008230 00008230 00000230 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 0000000a 000082a8 000082a8 000002a8 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000020 000082b4 000082b4 000002b4 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rel.dyn 00000008 000082d4 000082d4 000002d4 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rel.plt 00000018 000082dc 000082dc 000002dc 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 0000000a 000082f4 000082f4 000002f4 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 0000003c 00008300 00008300 00000300 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .text 00000134 0000833c 0000833c 0000033c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .fini 00000006 00008470 00008470 00000470 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .rodata 00000004 00008478 00008478 00000478 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .ARM.exidx 00000008 0000847c 0000847c 0000047c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .eh_frame 00000004 00008484 00008484 00000484 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .init_array 00000004 00010488 00010488 00000488 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .fini_array 00000004 0001048c 0001048c 0000048c 2**2
CONTENTS, ALLOC, LOAD, DATA
20 .jcr 00000004 00010490 00010490 00000490 2**2
CONTENTS, ALLOC, LOAD, DATA
21 .dynamic 00000108 00010494 00010494 00000494 2**2
CONTENTS, ALLOC, LOAD, DATA
22 .got 0000001c 0001059c 0001059c 0000059c 2**2
CONTENTS, ALLOC, LOAD, DATA
23 .data 00000010 000105b8 000105b8 000005b8 2**2
CONTENTS, ALLOC, LOAD, DATA
24 .bss 0000000c 000105c8 000105c8 000005c8 2**2
ALLOC
25 .comment 0000001d 00000000 00000000 000005c8 2**0
CONTENTS, READONLY
26 .ARM.attributes 00000033 00000000 00000000 000005e5 2**0
CONTENTS, READONLY
可以看到也是有.bss节的,而且大小为0,看FileOffset可知.bss的起始大小是0x5c8,.comment也是0x5c8,所以.bss是一个字都没有占到,
0 2 4 6 8 a c e
00005b0 8300 0000 0000 0000 | 0000 0000 0000 0000
00005c0 3344 1122 ccdd aabb | 4347 3a43 2820 6544
可见,它也是满足这个规律,也即全局变量放.data,没赋值的全局变量放.bss(只是占虚拟内存而已),代码和局部变量放.text。
对这俩静态变量的操作也是类似: