Linux下进程内存分布

最近学习了kprobe与uprobe,顺便复习一下linux系统下进程的内存分布以加深理解。

进程空间

一个标准的32位linux程序在运行时,在内存中的空间分布如下图所示:

.text段(代码段):

该部分存储程序的可执行代码,即cpu指令,默认情况下该段为只读段,不可修改,但利用内核的一些机制是可以代码段的内容,例如uprobe等机制。

.data数据段:

该部分存储在编译时就已经初始化了的全局和静态变量,在程序运行时会加载到内存空间中。该部分的内容在编译后会存在于elf程序文件中。

.bss段:

该部分存储未初始化的全局和静态变量,在程序运行时,该段内容会被初始化为0,在elf程序文件中不存在,但在程序运行时会占据虚拟内存空间。

堆空间:

程序中调用malloc或new分配的内存空间。按照地址从小到大的方式增长。当堆空间不足时,会通过系统调用brk将堆空间扩大。

动态链接库 (Dynamically Linked Libraries):

当程序使用了动态链接库的话,该动态链接库会被加载到堆地址空间上方。

栈 (Stack):

用于存储局部变量,函数调用信息,函数返回地址。栈地址一般从高地址向低地址增长,默认情况下栈的大小是有限制的,但可以修改。

         在linux系统下可以通过ulimit

–a查看进程的栈大小空间,默认为8M,可以通过ulimit –s xxx修改进程默认栈大小,ulimit调整栈大小后会影响系统所有程序。

         此外在编译程序时也可以指定栈大小(只会影响当前程序),即通过链接选项-Wl,-z,stack-size说明程序的栈大小。例如:

通过编译时设置栈大小只影响当前进程,不影响其他进程(首限于系统硬限制,即受限于ulimit –aH查询到的限制信息)。

         在编写代码时如果函数递归层次较深或在函数内部分配的局部变量太大都会导致栈越界从而造成程序异常。

可以通过nm命令可以查看elf程序中不同符号所在的位置:

nm命令输出的符号表类型含义如下:

Kernel空间

最高1G(32位系统下)空间为内核空间,用户态程序不能直接访问,如果访问则出现异常。内核态代码通过系统调用的方式执行。在Linux中,所有处理器的内核空间是被映射到一个相同的、连续的物理地址上。

在linux系统中,每个程序的内存分布相同,使得远程利用安全漏洞变得轻而易举,例如利用库函数在每个进程的内存空间中地址相同,或栈位置相同等特点攻击。 为了避免这种情况,linux系统引入了地址随机化功能,即在堆栈、内存映射段和堆的起始地址上添加偏移量,实现了堆栈、内存映射段和堆的随机化。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容