文章目录
  1. 1. 进程地址空间
  2. 2. 栈剖析

进程地址空间

Linux使用虚拟内存机制来管理计算机中的物理内存.
每个进程的内存空间都是独立的(在物理地址空间上),假如在32位系统中,进程虚拟地址的起始地址都是0x08048000h
对于同时运行的多个进程而言,就像运行在自己的内存小宇宙中,他们都认为其内存地址
开始于同一个地址。

内核接受任意程序发出的虚拟内存请求,并将这个虚拟内存转换到RAM中某处物理内存地址。

在32位系统中,进程的虚拟地址空间大小是4GB, 默认0~3G是用户空间,3~4G是内核空间。

32位系统,地址空间的分配如下图所示:

linux process memory

栈剖析

栈底位于高地址(不能高于0xBFFFFFFFh), 栈顶位于低地址(ESP指向栈顶),栈向下生长。

linux加载程序时,将大量的信息放入栈中, 包括可执行程序的完成路径,命令行参数和环境变量。

程序启动时,栈里面存放的内容按照下图的方式组织:

linux stack info, when program starts
图片来自于<<Assembly Language Step-By-Step: Programming with linux 3rd Edition>>

下面通过一个实验来检验:

test.c

1
2
3
4
int main(int argc, char *argv[])
{
return 0;
}

通过gdb查看程序启动时的栈信息

1
2
3
4
5
6
7
8
9
10
11
12
13
$ gdb ./test
GNU gdb (GDB) 7.11.1
... ...
Reading symbols from ./test...(no debugging symbols found)...done.
(gdb) set args a b c arg1 arg2 arg3
(gdb) b _start
Breakpoint 1 at 0x4003b0
(gdb) r
Starting program: /home/caodan/test a b c arg1 arg2 arg3
Breakpoint 1, 0x00000000004003b0 in _start ()
(gdb) info registers rsp
rsp 0x7fffffffe780 0x7fffffffe780

由于在64bit系统上,所以栈顶寄存器是rsp,而不是esp, rsp的值为:0x7fffffffe780
dump当前的栈信息, x/70xg的含义: x表示eXamine memory, 70表示需要显示70个单元的内容
x表示以16进制显示, g表示每个单元的长度为8个字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
(gdb) x/70xg 0x7fffffffe780
0x7fffffffe780: 0x0000000000000007 0x00007fffffffeaab
0x7fffffffe790: 0x00007fffffffeabd 0x00007fffffffeabf
0x7fffffffe7a0: 0x00007fffffffeac1 0x00007fffffffeac3
0x7fffffffe7b0: 0x00007fffffffeac8 0x00007fffffffeacd
0x7fffffffe7c0: 0x0000000000000000 0x00007fffffffead2
0x7fffffffe7d0: 0x00007fffffffeadd 0x00007fffffffeaef
0x7fffffffe7e0: 0x00007fffffffeb2d 0x00007fffffffeb44
0x7fffffffe7f0: 0x00007fffffffeb68 0x00007fffffffeb7f
0x7fffffffe800: 0x00007fffffffeb8f 0x00007fffffffeb9a
0x7fffffffe810: 0x00007fffffffebb2 0x00007fffffffebc4
0x7fffffffe820: 0x00007fffffffebd6 0x00007fffffffebf7
0x7fffffffe830: 0x00007fffffffec03 0x00007fffffffec2c
0x7fffffffe840: 0x00007fffffffec3c 0x00007fffffffec98
0x7fffffffe850: 0x00007fffffffeca4 0x00007fffffffeccd
0x7fffffffe860: 0x00007fffffffed12 0x00007fffffffed28
0x7fffffffe870: 0x00007fffffffed44 0x00007fffffffedac
0x7fffffffe880: 0x00007fffffffedb6 0x00007fffffffedc5
0x7fffffffe890: 0x00007fffffffede9 0x00007fffffffedfc
0x7fffffffe8a0: 0x00007fffffffee0d 0x00007fffffffee22
0x7fffffffe8b0: 0x00007fffffffee37 0x00007fffffffee48
0x7fffffffe8c0: 0x00007fffffffee5d 0x00007fffffffee66
0x7fffffffe8d0: 0x00007fffffffee77 0x00007fffffffee7f
0x7fffffffe8e0: 0x00007fffffffee91 0x00007fffffffeea0
0x7fffffffe8f0: 0x00007fffffffeecc 0x00007fffffffeedb
0x7fffffffe900: 0x00007fffffffeef5 0x00007fffffffef09
0x7fffffffe910: 0x00007fffffffef3f 0x00007fffffffef4c
0x7fffffffe920: 0x00007fffffffef57 0x00007fffffffef76
0x7fffffffe930: 0x00007fffffffef8a 0x00007fffffffefa4
0x7fffffffe940: 0x00007fffffffefcd 0x0000000000000000
0x7fffffffe950: 0x0000000000000021 0x00007ffff7ffa000
0x7fffffffe960: 0x0000000000000010 0x00000000bfebfbff
0x7fffffffe970: 0x0000000000000006 0x0000000000001000
0x7fffffffe980: 0x0000000000000011 0x0000000000000064
0x7fffffffe990: 0x0000000000000003 0x0000000000400040
0x7fffffffe9a0: 0x0000000000000004 0x0000000000000038

命令行参数的个数:

第一个内存单元中的值是7, 表示命令行参数的个数为7.

命令行参数的地址信息:

1
2
3
4
5
6
7
8
9
10
11
(gdb) x/s 0x00007fffffffeaab
0x7fffffffeaab: "/home/caodan/test"
(gdb) x/s 0x00007fffffffeabd
0x7fffffffeabd: "a"
(gdb) x/s 0x00007fffffffeabf
0x7fffffffeabf: "b"
(gdb) x/s 0x00007fffffffeac1
0x7fffffffeac1: "c"

最后一个命令行参数地址的下一个内存单元中的值是一个空指针,用来分隔命令行参数与环境变量

环境变量:

1
2
3
4
5
6
7
8
(gdb) x/s 0x00007fffffffead2
0x7fffffffead2: "XDG_VTNR=2"
(gdb) x/s 0x00007fffffffeadd
0x7fffffffeadd: "XDG_SESSION_ID=c2"
(gdb) x/s 0x00007fffffffeaef
0x7fffffffeaef: "TERMINATOR_UUID=urn:uuid:ccfa742b-66a3-4731-afba-07604b68d670"
文章目录
  1. 1. 进程地址空间
  2. 2. 栈剖析