【OS】Linux Process Memory的探究
前言
刷B站刷到了南大OS的课程,不得不说酒吧舞的教育水平真滴高,狠狠的看了一些关于进程地址相关的课程。
进程地址空间
1.导言
先导入两个问题:
-
如下的程序会输出什么?
#include<stdio.h> int main() { printf("%p\n", main); }
-
如果生成一个随机指针,什么情况会segmentation fault?
chat *ptr = random(); *p;
要解决上述两个问题,我们可以向进程空间中尝试了解。
那么,在Linux中,一个进程的地址空间是如何映射的?可以使用什么样的手段去查看某个进程的地址分配呢?
2.手动解决第一个问题
实践是检验真理的唯一标准,我们可以通过编译的方式来查看第一个问题的答案。
-
动态编译
gcc -o libc_ main.c
-
静态编译
gcc --static -o static_ main.c
-
写成一个Makefile
all: clean static libc clean: rm -rf static_ libc_ static: gcc --static -o static_ main.c libc: gcc -o libc_ main.c
运行两个程序,静态编译的结果每次都是相同的0x401745
,而动态编译出来的结果是0x55ff1b6ff149
,并且每次除了后3位不变其他都是会变的。
(之所以动态编译的main函数地址会变,是因为gcc编译的选项默认开启了PIE的保护手段,会将代码段的函数地址给随机化)
3.尝试分析结果
上述的实验结果已经看到了,那么为什么会这样呢?同时0x40开头的地址和0x55开头的地址分别是什么?
这些问题的答案我们不妨使用gdb来调试查看
针对静态编译的文件,进行starti
的操作,来到起点函数,随后执行vmmap
进行查看
我这里可以执行vmmap是因为安装了gdb的插件pwndbg
可以非常鲜明的看到当前的内存状态。vmmap
函数的底层是通过读取/proc/[pid]/maps
这个文件来进行内存的查看的,我们直接cat这个文件来看看
通过ps
来读取static_
这个文件的pid,随后进行maps的查看
我们的main函数地址就在0x401000~0x498000
这一段代码段中,具有可执行权限。
在main
函数的位置打个断点,然后continue
到main函数的开始部分,查看maps
我们发现0x4c5000
这个具有可读可写的段存放的其实是got
表,同时0x4c8000
开始的一段heap
内存在经历_start
函数之后被扩容了
随后就是0x7f
开头的地址了,那么这里的vvar、vdso
分别是什么呢?
(stack我们知道就是执行函数调用栈的一个内存数据结构)
看玩静态编译的程序后,我们再来看看动态编译的程序!