- 浏览: 43774 次
- 来自: 杭州
-
文章分类
最新评论
转自http://mqzhuang.iteye.com/blog/901602
内存管理是操作系统的核心之一,最近在研究内核的内存管理以及 C 运行时库对内存的分配和管理,涉及到进程在内存的布局,在此对进程的内存布局做一下总结:
1. 32 位模式下的 linux 内存布局
图上的各个部分描述得比较清楚,不需再做过多的描述。从上图可以看到,栈至顶向下扩展,并且栈是有界的。堆至底向上扩展, mmap 映射区域至顶向下扩展, mmap 映射区域和堆相对扩展,直至耗尽虚拟地址空间中的剩余区域,这种结构便于 C 运行时库使用 mmap 映射区域和堆进行内存分配。上图的布局形式是在内核 2.6.7 以后才引入的,这是 32 位模式下的默认内存布局形式。看看 cat 命令在 2.6.36 上内存布局:
08048000-08051000 r-xp 00000000 08:01 786454 /bin/cat
08051000-08052000 r--p 00008000 08:01 786454 /bin/cat
08052000-08053000 rw-p 00009000 08:01 786454 /bin/cat
08053000-08074000 rw-p 00000000 00:00 0 [heap]
b73e3000-b75e3000 r--p 00000000 08:01 400578 /usr/lib/locale/locale-archive
b75e3000-b75e4000 rw-p 00000000 00:00 0
b75e4000-b773b000 r-xp 00000000 08:01 1053967 /lib/libc-2.12.1.so
b773b000-b773c000 ---p 00157000 08:01 1053967 /lib/libc-2.12.1.so
b773c000-b773e000 r--p 00157000 08:01 1053967 /lib/libc-2.12.1.so
b773e000-b773f000 rw-p 00159000 08:01 1053967 /lib/libc-2.12.1.so
b773f000-b7742000 rw-p 00000000 00:00 0
b774f000-b7750000 r--p 002a1000 08:01 400578 /usr/lib/locale/locale-archive
b7750000-b7752000 rw-p 00000000 00:00 0
b7752000-b7753000 r-xp 00000000 00:00 0 [vdso]
b7753000-b776f000 r-xp 00000000 08:01 1049013 /lib/ld-2.12.1.so
b776f000-b7770000 r--p 0001b000 08:01 1049013 /lib/ld-2.12.1.so
b7770000-b7771000 rw-p 0001c000 08:01 1049013 /lib/ld-2.12.1.so
bfbed000-bfc0e000 rw-p 00000000 00:00 0 [stack]
可以看到,栈和 mmap 映射区域并不是从一个固定地址开始,并且每次的值都不一样,这是程序在启动时随机改变这些值的设置,使得使用缓冲区溢出进行攻击更加困难。当然也可以让程序的栈和 mmap 映射区域从一个固定位置开始,只需要设置全局变量 randomize_v a_space 值为 0 ,这个变量默认值为 1 。用户可以通过设置 /proc/sys/kernel/randomize_va_space 来停用该特性,也可以用如下命令:
sudo sysctl -w kernel.randomize_va_space=0
设置 randomize_va_space 为 0 后,再看看 cat 的内存布局:
08048000-08051000 r-xp 00000000 08:01 786454 /bin/cat
08051000-08052000 r--p 00008000 08:01 786454 /bin/cat
08052000-08053000 rw-p 00009000 08:01 786454 /bin/cat
08053000-08074000 rw-p 00000000 00:00 0 [heap]
b7c72000-b7e72000 r--p 00000000 08:01 400578 /usr/lib/locale/locale-archive
b7e72000-b7e73000 rw-p 00000000 00:00 0
b7e73000-b7fca000 r-xp 00000000 08:01 1053967 /lib/libc-2.12.1.so
b7fca000-b7fcb000 ---p 00157000 08:01 1053967 /lib/libc-2.12.1.so
b7fcb000-b7fcd000 r--p 00157000 08:01 1053967 /lib/libc-2.12.1.so
b7fcd000-b7fce000 rw-p 00159000 08:01 1053967 /lib/libc-2.12.1.so
b7fce000-b7fd1000 rw-p 00000000 00:00 0
b7fde000-b7fdf000 r--p 002a1000 08:01 400578 /usr/lib/locale/locale-archive
b7fdf000-b7fe1000 rw-p 00000000 00:00 0
b7fe1000-b7fe2000 r-xp 00000000 00:00 0 [vdso]
b7fe2000-b7ffe000 r-xp 00000000 08:01 1049013 /lib/ld-2.12.1.so
b7ffe000-b7fff000 r--p 0001b000 08:01 1049013 /lib/ld-2.12.1.so
b7fff000-b8000000 rw-p 0001c000 08:01 1049013 /lib/ld-2.12.1.so
bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
可以看出,栈和 mmap 区域都从固定位置开始了, stack 的起始位置为 0x c0000000 , mmap 区域的起始位置为 0x b8000000 ,可见系统为 stack 区域保留了 128M 内存地址空间。
在某些情况下,设置 randomize_va_space 为 0 ,便于对系统做一些针对性的研究,例如:进程的内存映射有个叫 vdso 的区域,也就是用 ldd 命令看到的那个” linux-gate.so.1 “,这块区域可以看成是内核用于实现 vsyscall 而创建的 virtual shared object ,遵循 elf 的格式,并且可以被用户程序访问。在设置 randomize_va_space 为 0 的情况下,使用如下命令就可以把这个区域 dump 出来看过究竟。如果不设置 randomize_va_space ,每次 vdso 的地址都是随机的,下面的命令也无能为力。
zhuang@ubuntu:~$ dd if=/proc/self/mem of=gate.so bs=4096 skip=$[0xb7fe1] count=1
dd: `/proc/self/mem': cannot skip to specified offset
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.00144225 s, 2.8 MB/s
zhuang@ubuntu:~$ objdump -d gate.so
gate.so: file format elf32-i386
Disassembly of section .text:
ffffe400 <__kernel_sigreturn>:
ffffe400: 58 pop %eax
ffffe401: b8 77 00 00 00 mov $0x77,%eax
ffffe406: cd 80 int $0x80
ffffe408: 90 nop
ffffe409: 8d 76 00 lea 0x0(%esi),%esi
ffffe40c <__kernel_rt_sigreturn>:
ffffe40c: b8 ad 00 00 00 mov $0xad,%eax
ffffe411: cd 80 int $0x80
ffffe413: 90 nop
ffffe414 <__kernel_vsyscall>:
ffffe414: 51 push %ecx
ffffe415: 52 push %edx
ffffe416: 55 push %ebp
ffffe417: 89 e5 mov %esp,%ebp
ffffe419: 0f 34 sysenter
ffffe41b: 90 nop
ffffe41c: 90 nop
ffffe41d: 90 nop
ffffe41e: 90 nop
ffffe41f: 90 nop
ffffe420: 90 nop
ffffe421: 90 nop
ffffe422: eb f3 jmp ffffe417 <__kernel_vsyscall+0x3>
ffffe424: 5d pop %ebp
ffffe425: 5a pop %edx
ffffe426: 59 pop %ecx
ffffe427: c3 ret
2. 32 为模式下的经典布局:
这种布局 mmap 区域与栈区域相对增长,这意味着堆只有 1GB 的虚拟地址空间可以使用,继续增长就会进入 mmap 映射区域,这显然不是我们想要的。这是由于 32 模式地址空间限制造成的,所以 内核引入了前一种虚拟地址空间的布局形式。但是对 64 位模式,提供了巨大的虚拟地址空间,这个布局就相当好。如果要在 2.6.7 以后的内核上使用 32 位模式内存经典布局,有两种办法可以设置:
方法一: sudo sysctl -w vm.legacy_va_layout=1
方法二: ulimit -s unlimited
同时设置 randomize_va_space 为 0 后, cat 的内存布局已经回到经典形式了:
08048000-08051000 r-xp 00000000 08:01 786454 /bin/cat
08051000-08052000 r--p 00008000 08:01 786454 /bin/cat
08052000-08053000 rw-p 00009000 08:01 786454 /bin/cat
08053000-08074000 rw-p 00000000 00:00 0 [heap]
40000000-4001c000 r-xp 00000000 08:01 1049013 /lib/ld-2.12.1.so
4001c000-4001d000 r--p 0001b000 08:01 1049013 /lib/ld-2.12.1.so
4001d000-4001e000 rw-p 0001c000 08:01 1049013 /lib/ld-2.12.1.so
4001e000-4001f000 r-xp 00000000 00:00 0 [vdso]
4001f000-40021000 rw-p 00000000 00:00 0
40021000-40022000 r--p 002a1000 08:01 400578 /usr/lib/locale/locale-archive
4002f000-40186000 r-xp 00000000 08:01 1053967 /lib/libc-2.12.1.so
40186000-40187000 ---p 00157000 08:01 1053967 /lib/libc-2.12.1.so
40187000-40189000 r--p 00157000 08:01 1053967 /lib/libc-2.12.1.so
40189000-4018a000 rw-p 00159000 08:01 1053967 /lib/libc-2.12.1.so
4018a000-4018e000 rw-p 00000000 00:00 0
4018e000-4038e000 r--p 00000000 08:01 400578 /usr/lib/locale/locale-archive
bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
3. 64 位模式下的内存布局
在 64 位模式下各个区域的起始位置是什么呢?对于 AMD64 , 内存布局采用的是经典模式, text 的起始地址为 0x0000000000400000 ,堆紧接着 BSS 段向上增长, mmap 映射区域开始位置一般设为 TASK_SIZE/3 ,
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
#define TASK_SIZE
(test_thread_flag(TIF_IA32) ? \
IA32_PAGE_OFFSET : TASK_SIZE_MAX)
#define STACK_TOP
TASK_SIZE
#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
计算一下可知, mmap 的开始区域地址为 0x0000 2AAAAAAAA000,栈顶地址为 0x0000 7FFFFFFFF000
发表评论
-
fedora系统删除多余内核
2013-01-22 21:32 1727查看本地系统安装的内核版本: $rpm -q ... -
Ubuntu change GNOME to XFCE problem
2012-12-14 16:10 827I'm now experiencing this probl ... -
c库中snprintf返回值误区
2012-11-07 22:05 7432最近看开源代码中发现一个问题,下面是发表在内核开 ... -
C++著名类库
2012-11-03 20:00 765转自 http://www.open-open ... -
Signal信号
2012-10-07 12:55 01) SIGHUP 本信号在用户终端连接(正常或非正常)结 ... -
Nginx
2012-09-20 23:38 0nginx (pronounced "engine ... -
Linux 灾难恢复
2012-09-19 21:57 0简介: Linux 发行版本 ... -
close_on_exec标志位
2012-09-06 21:33 2500close_on_exec是一个进程所有文件描述 ... -
Linux进程地址空间的探究解析
2012-08-08 23:35 0我们知道,在32位机器上 linux操作系统中的进程的地址空 ... -
git使用
2012-08-08 23:23 0我认为每个学过Git的人都应该做过类似这种笔记,因为Git命令 ... -
select, poll和epoll的区别
2012-07-31 21:34 0随着2.6内核对epoll的完全支持,网络上很多的文章和 ... -
linux多线程编程
2012-07-28 23:09 0本篇总结POSIX线程。可以用多个线程在单进程环境中执行多个任 ... -
select 和 epoll区别
2012-07-27 23:16 0最近有朋友在面试的时候被问了select 和epoll效率差的 ... -
echo显示变色
2012-07-24 17:07 0先来熟悉一下echo,如下: 名称 ... -
换行符的使用
2012-07-24 14:07 0Have you ever opened a s ... -
How to create and apply a patch with Git
2012-07-24 13:55 0Git is quite common now ... -
Facebook Folly源代码分析
2012-07-23 21:33 0Folly 是 Facebook 的一个开源C++11组件库, ... -
浅谈GCC预编译头技术
2012-07-23 09:51 893——谨以此文,悼念我 ... -
MySQL索引背后的数据结构及算法原理
2012-07-21 22:37 0转自 http://blog.jobbole.com/2400 ... -
patch文件的制作与使用
2012-07-01 18:43 2110创建补丁文件: 比如一个工程目录为project-o ...
相关推荐
2.1 X86平台Linux进程内存布局 2.1.1 32位模式下进程内存经典布局 2.1.2 32位模式下进程默认内存布局 2.1.3 64位模式下进程内存布局 2.2 操作系统内存分配的相关函数 2.2.1 Heap操作相关函数 2.2.2 Mmap映射...
linux进程的一切知识.zip 进程占用的内存空间布局,虚拟空间地址分布 进程启动的3种方式 监控子进程的状态 进程的终止 僵尸进程
1.4 Linux内存布局 21 1.5 内核空间和用户空间 23 1.5.1 初始化临时内核页表 24 1.5.2 永久内核页表的初始化 32 1.5.3 第一次进入用户空间 41 1.5.4 内核映射机制实例 44 1.6 固定映射的线性地址 48 1.7 高端内存...
4.2 Linux中的进程概述 4.3 task_struct结构描述 4.4 task_struct结构在内存中的存放 4.5 进程组织的方式 4.6 内核线程 4.7 进程的权能 4.8 内核同步 第五章进程调度 5.1 Linux时间系统 5.2 时钟中断 5.3 Linux的...
在Linux系统中, 内核进程和用户进程所占的虚拟内存比例是1:3,而Windows系统为2:2(通过设置Large-Address-Aware Executables标志也可为1:3)。这并不意味着内核使用那么多物理内存,仅表示它可支配这部分地址空间,...
3.4.3 Linux进程调度时机 50 3.4.4 进程调度的依据 51 3.4.5 调度函数schedule()的实现 52 3.5 进程的创建 54 3.5.1 创建进程 55 3.5.2 线程及其创建 56 3.6 与进程相关的系统调用及其应用 58 3.6.1 fork系统调用 58...
5.3.2 Linux进程调度时机 5.3.3 进程调度的依据 5.3.4 进程可运行程度的衡量 5.3.5 进程调度的实现 5.4 进程切换 5.4.1 硬件支持 5.4.2 进程切换 第六章 Linux内存管理 6.1 Linux的内存管理概述 6.1.1 ...
《linux/unix系统编程手册(上、下册)》总共分为64章,主要讲解了高效读写文件,对信号、时钟和定时器的运用,创建进程、执行程序,编写安全的应用程序,运用posix线程技术编写多线程程序,创建和使用共享库,运用...
Linux 的内核是操作系统的核心部分,它负责管理硬件资源、进程调度、内存管理等。Linux 的内核版本号是 2.4.20-8。 4. Shell Shell 是 Linux 的命令行解释器,它提供了一个交互式的命令行界面。Shell 的功能包括...
5.1.6 各服务进程的作用 5.2 建立PPP连接和配置PPP服务器 5.2.1 有关PPP的基础知识 5.2.2 使用PPP拨号上网 5.2.3 配置PPP服务器 5.3 配置DNS服务器 5.3.1 DNS(Domain Name System)简介 5.3.2 域名服务系统 5.3.3 ...
不管怎样,下面是一个Linux进程的标准的内存段布局:当计算机开心、安全、可爱、正常的运转时,那么上图显示的内存段起始虚拟地址在几乎每个进程中都是一样的。也许是
进程管理命令是指用于管理Ubuntu进程的命令,包括查看当前内存使用情况、连续监视内存使用情况、动态显示进程之行情况等。 虚拟机安装Linux及Ubuntu是一个非常重要的知识点,对于IT行业的从业人员来说,是一个必备...
《Linux/UNIX系统编程手册(上、下册)》总共分为64章,主要讲解了高效读写文件,对信号、时钟和定时器的运用,创建进程、执行程序,编写安全的应用程序,运用POSIX线程技术编写多线程程序,创建和使用共享库,运用...
《Linux/UNIX系统编程手册(上、下册)》总共分为64章,主要讲解了高效读写文件,对信号、时钟和定时器的运用,创建进程、执行程序,编写安全的应用程序,运用POSIX线程技术编写多线程程序,创建和使用共享库,运用...
知识点:Linux 进程的内存布局,进程的内存空间的组成部分,栈、堆、数据段和代码段的作用和区别。 9. 简述 SSL 协议双向认证的过程。 知识点:SSL 协议的双向认证过程,客户端和服务器端的认证机制,数字证书的...
18.5 内存布局374 18.6 内核移植375 18.7 嵌入式驱动程序376 18.7.1 闪存377 18.7.2 uart377 18.7.3 按钮和滚轮378 18.7.4 pcmcia/cf378 18.7.5 sd/mmc378 18.7.6 usb378 18.7.7 rtc378 18.7.8...
367 第18章 嵌入式linux 369 18.1 挑战 369 18.2 元器件选择 370 18.3 工具链 371 18.4 bootloader 372 18.5 内存布局 374 18.6 内核移植 375 18.7 嵌入式驱动程序 376 18.7.1 闪存 377 18.7.2 uart 377 ...
采集网络上关于Linux系统相关的优秀资源。 目录 ...Anatomy of a Program in Memory:程序的内存布局 How The Kernel Manages Your Memory:内核如何管理内存 Understanding the Memory Layout of L