- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
linux 进程内存布局
linux 进程内存布局
在多任务操作系统中的每一个进程都运行在一个属于它自
己的内存沙盘中。这个沙盘就是虚拟地址空间( virtual
address space
),在
32
位模式下它总是一个
4GB
的内存地
址块。这些虚拟地址通过页表( page table )映射到物理内
存,页表由操作系统维护并被处理器引用。每一个进程拥有一套属于它自己的页表,但是还有一个隐情。只要虚拟地址被使能,那么它就会作用于这台机器上运行的所有软件,包括内核本身。因此一部分虚拟地址必须保留给内核使用:这并不意味着内核使用了那么多的物理内存,仅表示它可支配
这么大的地址空间, 可根据内核需要, 将其映射到物理内存。
内核空间在页表中拥有较高的特权级 ( ring 2 或以下),因此
只要用户态的程序试图访问这些页,就会导致一个页错误
page fault )。在 Linux 中,内核空间是持续存在的,并且在所有进程中都映射到同样的物理内存。内核代码和数据总是可寻址的,随时准备处理中断和系统调用。与此相反,用户模式地址空间的映射随进程切换的发生而不断变化:色区域表示映射到物理内存的虚拟地址,而白色区域表示未映射的部分。 在上面的例子中, Firefox 使用了相当多的虚拟地址
空间,因为它是传说中的吃内存大户。地址空间中的各个条
带对应于不同的内存段( memory segment ),如:堆、栈之类的。记住,这些段只是简单的内存地址范围, 与 Intel 处理器的段没有关系。不管怎样,下面是一个 Linux 进程的标准
的内存段布局: 当计算机开心、 安全、可爱、正常的运转时,几乎每一个进程的各个段的起始虚拟地址都与上图完全一致,这也给远程发掘程序安全漏洞打开了方便之门。一个发
掘过程往往需要引用绝对内存地址: 栈地址,库函数地址等。远程攻击者必须依赖地址空间布局的一致性,摸索着选择这
些地址。如果让他们猜个正着,有人就会被整了。因此,地
址空间的随机排布方式逐渐流行起来。 Linux 通过对栈内存
映射段、堆的起始地址加上随机的偏移量来打乱布局。不幸的是, 32 位地址空间相当紧凑,给随机化所留下的空当不大,削弱了这种技巧的效果。进程地址空间中最顶部的段是栈,大多数编程语言将之用于存储局部变量和函数参数。调
用一个方法或函数会将一个新的栈桢( stack frame )压入栈
中。栈桢在函数返回时被清理。也许是因为数据严格的遵从 LIFO 的顺序,这个简单的设计意味着不必使用复杂的数据结构来追踪栈的内容,只需要一个简单的指针指向栈的顶端
即可。因此压栈( pushing )和退栈( popping )过程非常迅
速、准确。另外,持续的重用栈空间有助于使活跃的栈内存
保持在 CPU 缓存中,从而加速访问。进程中的每一个线程
都有属于自己的栈。通过不断向栈中压入的数据,超出其容
量就有会耗尽栈所对应的内存区域。这将触发一个页故障
page fault ),并被 Linux 的 expand_stack() 处理,它会调用 acct_stack_growth() 来检查是否还有合适的地方用于栈
的增长。如果栈的大小低于 RLIMIT_STACK (通常是 8MB ),那么一般情况下栈会被加长,程序继续愉快的运行,感觉不
到发生了什么事情。这是一种将栈扩展至所需大小的常规机
制。然而,如果达到了最大的栈空间大小, 就会栈溢出( stack overflow ),程序收到一个段错误 (Segmentation Fault )。当映射了的栈区域扩展到所需的大小后,它就不会再收缩回去,
即使栈不那么满了。这就好比联邦预算,它总是在增长的。动态栈增长是唯一一种访问未映射内存区域(图中白色区域)而被允许的情形。其它任何对未映射内存区域的访问都会触发页故障,从而导致段错误。一些被映射的区域是只读的,因此企图写这些区域也会导致段错误。在栈的下方,是我们的内存映射段。此处,内核将文件的内容直接映射到内存。
任何应用程序都可以通过 Linux 的 mmap() 系统调用(实现)或 Windows 的 CreateFileMapping()/MapViewOfFile()
请求这种映射。内存映射是一种方便高效的文件 I/O 方式,
所以它被用于加载动态库。创建一个不对应于任何文件的匿
名内存映射也是可能的,此方法用于存放程序的数据。在
Linux 中,如果你通过 malloc() 请求一大块内存, C 运行库
将会创建这样一个匿名映射而不是使用堆内存。 ‘大块’意味着
比 MMAP_THRESHOLD 还大,缺省是 128KB ,可以通过
mallopt() 调整。说到堆,它是接下来的一块地址空间。与栈
一
文档评论(0)