/proc/$pid/maps文件中各个空间段的意义

一、从/proc/self/maps中看到的内存布局

在这个输出中,可以很容易看到一个so文件中有一个"---p"属性的区间段,它们对应哪些文件内容,数据从哪里来?在stackoverflow网站上也有一个这样的提问,只是还没有人解答。
tsecer@harry: cat /proc/self/maps
00400000-0040b000 r-xp 00000000 fd:01 15433 /usr/bin/cat
0060b000-0060c000 r--p 0000b000 fd:01 15433 /usr/bin/cat
0060c000-0060d000 rw-p 0000c000 fd:01 15433 /usr/bin/cat
00877000-00898000 rw-p 00000000 00:00 0 [heap]
7fab3ae42000-7fab4136b000 r--p 00000000 fd:01 24801 /usr/lib/locale/locale-archive
7fab4136b000-7fab4136d000 r-xp 00000000 fd:01 25150 /usr/lib64/libdl-2.17.so
7fab4136d000-7fab4156d000 ---p 00002000 fd:01 25150 /usr/lib64/libdl-2.17.so
7fab4156d000-7fab4156e000 r--p 00002000 fd:01 25150 /usr/lib64/libdl-2.17.so
7fab4156e000-7fab4156f000 rw-p 00003000 fd:01 25150 /usr/lib64/libdl-2.17.so
7fab4156f000-7fab41729000 r-xp 00000000 fd:01 25054 /usr/lib64/libc-2.17.so
7fab41729000-7fab41928000 ---p 001ba000 fd:01 25054 /usr/lib64/libc-2.17.so
7fab41928000-7fab4192c000 r--p 001b9000 fd:01 25054 /usr/lib64/libc-2.17.so
7fab4192c000-7fab4192e000 rw-p 001bd000 fd:01 25054 /usr/lib64/libc-2.17.so
7fab4192e000-7fab41933000 rw-p 00000000 00:00 0
7fab41933000-7fab41954000 r-xp 00000000 fd:01 24864 /usr/lib64/ld-2.17.so

二、从lib文件看布局

从生成的so文件来看,两个LOAD节的Align都是0x20000,也就是2Mb的对齐,并且在第二个LOAD中,它的VirtAddr地址0x0000000000200db8,和文件偏移量0x0000000000000db8的起始地址相差了2M,而"---p"的区间段就是两个LOAD区间中空闲的内存空间。
tsecer@harry: cat -n maps---p.cpp
1 int gx = 1;
2 int gy;
3 int foo()
4 {
5 return gx + gy;
6 }
tsecer@harry: g++ maps---p.cpp -shared -fpic -o libmaps.so
tsecer@harry: readelf -l libmaps.so

Elf 文件类型为 DYN (共享目标文件)
入口点 0x630
共有 7 个程序头,开始于偏移量64

程序头:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000007c4 0x00000000000007c4 R E 200000
LOAD 0x0000000000000db8 0x0000000000200db8 0x0000000000200db8
0x0000000000000274 0x0000000000000280 RW 200000
DYNAMIC 0x0000000000000dd8 0x0000000000200dd8 0x0000000000200dd8
0x00000000000001f0 0x00000000000001f0 RW 8
NOTE 0x00000000000001c8 0x00000000000001c8 0x00000000000001c8
0x0000000000000024 0x0000000000000024 R 4
GNU_EH_FRAME 0x0000000000000740 0x0000000000000740 0x0000000000000740
0x000000000000001c 0x000000000000001c R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x0000000000000db8 0x0000000000200db8 0x0000000000200db8
0x0000000000000248 0x0000000000000248 R 1

三、这个Align为什么这么大

可以看到,这个对齐其实是在链接器中设置的,估计是为了兼容SO可以运行的平台,例如有些页面为2M的平台。这个大小可以通过链接器选项来设置
tsecer@harry: g++ maps---p.cpp -shared -fpic -o libmaps.so -Wl,-z,max-page-size=4096
tsecer@harry: readelf -l libmaps.so

Elf 文件类型为 DYN (共享目标文件)
入口点 0x630
共有 7 个程序头,开始于偏移量64

程序头:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000007c4 0x00000000000007c4 R E 1000
LOAD 0x0000000000000db8 0x0000000000001db8 0x0000000000001db8
0x0000000000000274 0x0000000000000280 RW 1000
DYNAMIC 0x0000000000000dd8 0x0000000000001dd8 0x0000000000001dd8
0x00000000000001f0 0x00000000000001f0 RW 8

四、运行下看内存布局

可以看到中间已经没有"---p"属性区间段
tsecer@harry: cat -n main.cpp
1 int main()
2 {
3 int foo();
4 return foo();
5 }
tsecer@harry: g++ main.cpp -L`pwd` -lmaps -g
tsecer@harry: LD_LIBRARY_PATH=`pwd` gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/harry/study/maps---p/a.out...done.
(gdb) b main
Breakpoint 1 at 0x4006c4: file main.cpp, line 4.
(gdb) r
Starting program: /home/harry/study/maps---p/./a.out

Breakpoint 1, main () at main.cpp:4
4 return foo();
Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.tl2.3.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc++-4.8.5-4.el7.x86_64
(gdb) info proc
process 21541
cmdline = '/home/harry/study/maps---p/./a.out'
cwd = '/home/harry/study/maps---p'
exe = '/home/harry/study/maps---p/a.out'
(gdb) shell cat /proc/21541/maps
00400000-00401000 r-xp 00000000 fd:10 31719450 /home/harry/study/maps---p/a.out
00600000-00601000 r--p 00000000 fd:10 31719450 /home/harry/study/maps---p/a.out
00601000-00602000 rw-p 00001000 fd:10 31719450 /home/harry/study/maps---p/a.out
……
7ffff7eef000-7ffff7ef0000 r-xp 00000000 fd:10 31719449 /home/harry/study/maps---p/libmaps.so
7ffff7ef0000-7ffff7ef1000 r--p 00000000 fd:10 31719449 /home/harry/study/maps---p/libmaps.so
7ffff7ef1000-7ffff7ef2000 rw-p 00001000 fd:10 31719449 /home/harry/study/maps---p/libmaps.so

五、"rw-p"为什么有两段

可以看到,在这个区间段的最后有两段,这一点也容易理解:
因为一些全局为初始化变量是位于bss段的,它们并不在文件中占用空间,需要在加载时清零。所以做文件映射就不能实现该功能(因为文件里没有对应的内容),所以这里其实是映射到了一个匿名的私有空间,逻辑地址空间和前面的连续。
7ffff7ad3000-7ffff7bbc000 r-xp 00000000 fd:01 25828 /usr/lib64/libstdc++.so.6.0.19
7ffff7bbc000-7ffff7dbc000 ---p 000e9000 fd:01 25828 /usr/lib64/libstdc++.so.6.0.19
7ffff7dbc000-7ffff7dc4000 r--p 000e9000 fd:01 25828 /usr/lib64/libstdc++.so.6.0.19
7ffff7dc4000-7ffff7dc6000 rw-p 000f1000 fd:01 25828 /usr/lib64/libstdc++.so.6.0.19
7ffff7dc6000-7ffff7ddb000 rw-p 00000000 00:00 0

posted on 2019-08-19 12:29  tsecer  阅读(2949)  评论(0编辑  收藏  举报

导航