一、程序构成
在学习Linux应用程序开发时,经常会遇到如下概念:代码段、数据段、BSS段等。BSS(Block Started by Symbol,又名:未初始化数据段)、堆(heap)、栈(stack)而这些部分也是构成Linux应用程序的重要组成部分。
二、内存布局
当Linux应用程序在内存中运行的时候,以上组成部分在内存中以如下图的方式布局。
- 从低地址到高地址分别为:代码段、数据段、BSS段、堆、栈
- 堆向高内存地址生长
- 栈向低内存地址生长
三、编写代码查看程序各段地址
编辑如下代码:addr.c
#include <stdio.h>
#include <malloc.h>
#include <string.h>
char a[64] = "welcome";
char b[64];
void main()
{
char *c = (char *)malloc(64);
int d = 76;
strcpy(b,"value b");
strcpy(c,"value c");
printf("var a address: 0x%16x \n",a);
printf("var b address: 0x%16x \n",b);
printf("var c address: 0x%16x \n",c);
printf("var d address: 0x%16x \n",&d);
while(1){;} }
编译、运行程序:
gcc -o addr -g addr.c
./addr
//输出如下:
var a address: 0x 601060
var b address: 0x 6010c0
var c address: 0x 6ab010
var d address: 0x 4715986c
另外打开一个shell 进行操作:
ps aux | grep ./addr
//这里输出如下
jet 4426 100 0.0 4356 640 pts/18 R+ 20:47 0:21 ./addr
jet 4439 0.0 0.0 15964 980 pts/19 S+ 20:47 0:00 grep --color=auto ./addr
//可以看出我们的进程PID 是 4426
抓取内存信息:
cat /proc/4426/maps
// 输出如下:(我这里是x64机器有点不太一样)
00400000-00401000 r-xp 00000000 08:01 7870415 /home/jet/study/lesson3_memory/addr
00600000-00601000 r--p 00000000 08:01 7870415 /home/jet/study/lesson3_memory/addr
00601000-00602000 rw-p 00001000 08:01 7870415 /home/jet/study/lesson3_memory/addr
006ab000-006cc000 rw-p 00000000 00:00 0 [heap]
7f73272bb000-7f732747b000 r-xp 00000000 08:01 12849622 /lib/x86_64-linux-gnu/libc-2.23.so
7f732747b000-7f732767b000 ---p 001c0000 08:01 12849622 /lib/x86_64-linux-gnu/libc-2.23.so
7f732767b000-7f732767f000 r--p 001c0000 08:01 12849622 /lib/x86_64-linux-gnu/libc-2.23.so
7f732767f000-7f7327681000 rw-p 001c4000 08:01 12849622 /lib/x86_64-linux-gnu/libc-2.23.so
7f7327681000-7f7327685000 rw-p 00000000 00:00 0
7f7327685000-7f73276ab000 r-xp 00000000 08:01 12845073 /lib/x86_64-linux-gnu/ld-2.23.so
7f732788b000-7f732788e000 rw-p 00000000 00:00 0
7f73278a8000-7f73278aa000 rw-p 00000000 00:00 0
7f73278aa000-7f73278ab000 r--p 00025000 08:01 12845073 /lib/x86_64-linux-gnu/ld-2.23.so
7f73278ab000-7f73278ac000 rw-p 00026000 08:01 12845073 /lib/x86_64-linux-gnu/ld-2.23.so
7f73278ac000-7f73278ad000 rw-p 00000000 00:00 0
7ffc4713a000-7ffc4715b000 rw-p 00000000 00:00 0 [stack]
7ffc471c6000-7ffc471c8000 r--p 00000000 00:00 0 [vvar]
7ffc471c8000-7ffc471ca000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
这里我们结合进程map信息和程序输出信息可以得出:
- 代码段位于 400000 - 401000
- 数据段位于 600000 - 601000
- BSS段位于 601000 - 602000
- 堆空间位于 6ab000 - 6cc000
- 栈空间地址非常高
四、变量存放段补充
.data段:
- 全局、已初始化
- 全局、静态、已初始化
- 局部、静态、初始化
.BSS段:
- 全局、未初始化
- 全局、静态、未初始化
- 局部、静态、未初始化
.code段:
- 全局、常量(const)
- 字符串常量
.stack段:
- 局部、初始化
- 局部、未初始化
- 局部、常量(const)
.heap段:
- malloc分配局部变量
注意:
可以通过下面命令读取相关程序的内存分配:
readelf -s addr
//输出如下:
Symbol table '.dynsym' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc@GLIBC_2.2.5 (2)
Symbol table '.symtab' contains 75 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400238 0 SECTION LOCAL DEFAULT 1
2: 0000000000400254 0 SECTION LOCAL DEFAULT 2
3: 0000000000400274 0 SECTION LOCAL DEFAULT 3
4: 0000000000400298 0 SECTION LOCAL DEFAULT 4
5: 00000000004002b8 0 SECTION LOCAL DEFAULT 5
6: 0000000000400330 0 SECTION LOCAL DEFAULT 6
7: 0000000000400376 0 SECTION LOCAL DEFAULT 7
8: 0000000000400380 0 SECTION LOCAL DEFAULT 8
9: 00000000004003a0 0 SECTION LOCAL DEFAULT 9
10: 00000000004003b8 0 SECTION LOCAL DEFAULT 10
11: 0000000000400400 0 SECTION LOCAL DEFAULT 11
12: 0000000000400420 0 SECTION LOCAL DEFAULT 12
13: 0000000000400460 0 SECTION LOCAL DEFAULT 13
14: 0000000000400470 0 SECTION LOCAL DEFAULT 14
15: 0000000000400684 0 SECTION LOCAL DEFAULT 15
16: 0000000000400690 0 SECTION LOCAL DEFAULT 16
17: 00000000004006f4 0 SECTION LOCAL DEFAULT 17
18: 0000000000400728 0 SECTION LOCAL DEFAULT 18
19: 0000000000600e10 0 SECTION LOCAL DEFAULT 19
20: 0000000000600e18 0 SECTION LOCAL DEFAULT 20
21: 0000000000600e20 0 SECTION LOCAL DEFAULT 21
22: 0000000000600e28 0 SECTION LOCAL DEFAULT 22
23: 0000000000600ff8 0 SECTION LOCAL DEFAULT 23
24: 0000000000601000 0 SECTION LOCAL DEFAULT 24
25: 0000000000601040 0 SECTION LOCAL DEFAULT 25
26: 00000000006010a0 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 SECTION LOCAL DEFAULT 27
28: 0000000000000000 0 SECTION LOCAL DEFAULT 28
29: 0000000000000000 0 SECTION LOCAL DEFAULT 29
30: 0000000000000000 0 SECTION LOCAL DEFAULT 30
31: 0000000000000000 0 SECTION LOCAL DEFAULT 31
32: 0000000000000000 0 SECTION LOCAL DEFAULT 32
33: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
34: 0000000000600e20 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__
35: 00000000004004a0 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
36: 00000000004004e0 0 FUNC LOCAL DEFAULT 14 register_tm_clones
37: 0000000000400520 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
38: 00000000006010a0 1 OBJECT LOCAL DEFAULT 26 completed.7585
39: 0000000000600e18 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fin
40: 0000000000400540 0 FUNC LOCAL DEFAULT 14 frame_dummy
41: 0000000000600e10 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_
42: 0000000000000000 0 FILE LOCAL DEFAULT ABS addr.c
43: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
44: 0000000000400818 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
45: 0000000000600e20 0 OBJECT LOCAL DEFAULT 21 __JCR_END__
46: 0000000000000000 0 FILE LOCAL DEFAULT ABS
47: 0000000000600e18 0 NOTYPE LOCAL DEFAULT 19 __init_array_end
48: 0000000000600e28 0 OBJECT LOCAL DEFAULT 22 _DYNAMIC
49: 0000000000600e10 0 NOTYPE LOCAL DEFAULT 19 __init_array_start
50: 00000000004006f4 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
51: 0000000000601000 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_
52: 0000000000400680 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
54: 0000000000601040 0 NOTYPE WEAK DEFAULT 25 data_start
55: 00000000006010c0 64 OBJECT GLOBAL DEFAULT 26 b
56: 00000000006010a0 0 NOTYPE GLOBAL DEFAULT 25 _edata
57: 0000000000400684 0 FUNC GLOBAL DEFAULT 15 _fini
58: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
60: 0000000000601040 0 NOTYPE GLOBAL DEFAULT 25 __data_start
61: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
62: 0000000000601048 0 OBJECT GLOBAL HIDDEN 25 __dso_handle
63: 0000000000400690 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
64: 0000000000400610 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
65: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc@@GLIBC_2.2.5
66: 0000000000601100 0 NOTYPE GLOBAL DEFAULT 26 _end
67: 0000000000400470 42 FUNC GLOBAL DEFAULT 14 _start
68: 0000000000601060 64 OBJECT GLOBAL DEFAULT 25 a
69: 00000000006010a0 0 NOTYPE GLOBAL DEFAULT 26 __bss_start
70: 0000000000400566 164 FUNC GLOBAL DEFAULT 14 main
71: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
72: 00000000006010a0 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__
73: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
74: 0000000000400400 0 FUNC GLOBAL DEFAULT 11 _init
通过输出结果可以分析数据段的分配。