有关可执行程序的内存布局的更多信息(进程)

时间:2009-12-27 20:15:15

标签: memory assembly process operating-system

我参加了三星的采访。他们询问了很多关于程序内存布局的问题。我对此几乎一无所知。

我用谷歌搜索了“可执行程序的内存布局”。 “进程的内存布局”。

我很惊讶地发现这些主题的信息不多。大多数结果都是论坛查询。我只是想知道为什么?

这些是我找到的几个链接:

  1. Run-Time Storage Organization
  2. Run-Time Memory Organization
  3. Memory layout of C process ^pdf^
  4. 我想从一本正确的书而不是一些网络链接中学到这一点。(兰迪海德也是一本书,但还有一本书)。在哪本书中我能找到清楚的&关于这个主题的更多信息?

    我也很奇怪,为什么操作系统的书不能在他们的书中涵盖这一点?我读了第6版的摊位。它只讨论了过程控制块。

    整个布局创建是linker的任务对吗?我在哪里可以阅读有关此过程的更多信息我希望从磁盘上的程序 COMPLETE 信息到处理器上的执行。

    修改

    最初,即使阅读了下面给出的答案,我也不清楚。最近,我在看完这些文章之后看到了这些文章,我明白了。

    帮助我理解的资源:

      
        
    1. www.tenouk.com/Bufferoverflowc/Bufferoverflow1b.html
    2.   
    3. 5部分PE文件格式教程:http://win32assembly.online.fr/tutorials.html
    4.   
    5. 优秀文章:http://www.linuxforums.org/articles/understanding-elf-using-readelf-and-objdump_125.html
    6.   
    7. PE Explorer:http://www.heaventools.com/
    8.   

    是的,“可执行程序的布局(PE / ELF)”!=“进程的内存布局”)。在第3个链接中找到自己。 :)

    在清除了我的概念之后,我的问题让我看起来很蠢。 :)

3 个答案:

答案 0 :(得分:7)

如何加载内容非常依赖于操作系统和使用的二进制格式,细节可能会变得很糟糕。有关二进制文件如何布局的标准,但它实际上取决于操作系统如何布置进程的内存。这可能是文档很难找到的原因。

回答你的问题:

  1. 书籍:
    • 如果您对流程如何记忆感兴趣,请查看Understanding the Linux Kernel。第3章讨论了进程描述符,创建进程和破坏进程。
    • 我所知道的唯一一本涵盖链接和加载的书是John Levine的Linkers and Loaders。有一个在线和印刷版本,所以检查出来。

  2. 可执行代码由编译器和链接器创建,但它是将操作系统放入操作系统所需的二进制格式的链接器。在Linux上,这种格式通常为ELF,在Windows和较旧的Unix上为COFF,在Mac OS X上为Mach-O。不过,这不是一个固定的清单。一些操作系统可以并且确实支持多种二进制格式。链接器需要知道输出格式以创建可执行文件。

  3. 进程的内存布局与二进制格式非常相似,因为很多二进制格式被设计为mmap'd,因此加载器的任务更容易。

    虽然这不是相当。二进制格式的某些部分(如静态数据)不直接存储在二进制文件中。相反,二进制文件只包含这些部分的大小。当进程加载到内存中时,加载器知道分配适当的内存量,但二进制文件不需要包含大的空部分。

    此外,进程的内存布局包括stackheap的一些空间,其中进程的调用帧和动态分配的内存进入。这些通常位于大地址空间的两端。

  4. 这实际上只是揭示了二进制文件如何加载的表面,并没有涉及动态库的任何内容。有关动态链接和加载工作的详细处理,请阅读How to Write Shared Libraries

答案 1 :(得分:2)

以下是从文件(* nix)执行程序的一种方法。

  • 创建过程(例如fork())。这为新进程提供了自己的内存映射。这包括在某些内存区域中的堆栈(通常在内存中的高位)。
  • 新进程调用exec()以使用新的可执行文件替换当前可执行文件(通常是shell)。通常,新的可执行文件.text(可执行代码和常量)和.data(r / w初始化变量)是为需求页面映射设置的,也就是说,它们根据需要映射到进程内存空间。通常,.text部分首先出现,然后是.data。 .bss部分(未初始化的变量)通常在.data部分之后分配。很多时候,当第一次访问包含bss变量的页面时,它被映射为返回一个零页面。堆通常在.bss部分之后的下一页边界处开始。堆栈随着堆栈的增长而在内存中长大(记住我通常说,有例外!)。

如果堆和堆栈发生冲突,通常会导致内存不足的情况,这就是堆栈通常放在高内存中的原因。

在没有内存管理单元的系统中,请求分页通常不可用,但通常使用相同的内存布局。

答案 2 :(得分:1)