【问题标题】:Data in executable file are on weird position可执行文件中的数据位于奇怪的位置
【发布时间】:2013-03-10 16:33:55
【问题描述】:

几天前我开始玩 PE 格式。我已经完成了小型 PE 加载器,它能够根据它们的虚拟地址将部分加载到内存中。例如,我在虚拟地址 0x1000 上有部分 .text,或者在 0x2000 上有部分 .data。使用我的小汇编代码,我在某个空闲位置 (0x10000) 加载了 PE 文件,并从它的位置加载了 PE 部分。所以,.text 部分在0x110000x10000 + 0x1000)上,.data0x12000 上等等......但是当我从.code 位置引用我在汇编中的数据时,我发现(在反汇编中)它指向0x402000。在互联网上,我发现了特定于每种图像类型的图像库之类的东西......但我不明白当有很多可执行文件在 Windows 中运行时,如何将.exe 加载到0x402000。有人为什么会这样,它是如何工作的,我如何在我非常基本的系统中理论上实现它?

请帮忙。

【问题讨论】:

    标签: c assembly linker exe portable-executable


    【解决方案1】:

    虚拟内存意味着您计算机上的每个进程都可以使用“相同”的地址,因为每个进程的地址空间都是独立的。进程 A 的 0x400000 被操作系统映射到与进程 B 的 0x400000 不同的物理地址,即使它们是相同的虚拟地址(不同的虚拟地址空间)。

    可执行文件的默认基地址是0x400000。您的链接器将基地址硬编码到可执行文件中,并将适当地调整地址引用。当程序启动时,您的可执行文件将被加载到该地址。您的汇编器或链接器应该为您提供更改此默认基地址的方法。

    请注意,另一方面,DLL 必须加载到唯一的地址,因为它们必须共存于同一个进程中。出于这个原因,DLL 通常是可重定位的,即它们在加载时可以具有任何基地址,以应对将它们放在唯一地址的要求。 (在系统上拥有多个不可重定位的 DLL 可能会导致问题,但在系统上拥有多个不可重定位的 .exe 则完全没有问题。)

    【讨论】:

    • 好的,操作系统如何执行正常的汇编指令来寻址不同的位置?这怎么可能?
    • 抱歉,不清楚。这是链接器的功能,而不是操作系统。我更新了答案。
    • 好的,但仍然。如果不是物理地址,CPU 怎么知道它应该从哪里读/写字节?
    • Read Wikipedia 和/或参加操作系统课程。这个话题太大了,无法在 SO 答案中涵盖。
    【解决方案2】:

    每个可执行文件都在自己的virtual address space 中运行。因此,即使两个可执行文件具有相同的 0x400000 映像库,它们驻留/使用不同的物理内存。把它想象成图像库的基础不同。

    要将模块的图像库加载到正在运行的进程中,您可以使用GetModuleHandle。它向模块返回一个句柄,该句柄恰好等于图像库。或者,您可以从 PE Headers IMAGE_OPTIONAL_HEADER 结构 (see here) 中的 ImageBase 字段中获取图像库。

    【讨论】:

    • 好的,操作系统如何执行正常的汇编指令来寻址不同的位置?这怎么可能?
    【解决方案3】:

    这是一个复杂的主题,但是由于虚拟内存和硬件辅助的进程分离,每个进程都被加载,并且给人的印象是它拥有自己的整个地址空间。因此所有的镜像库都可以从同一个地址开始,因为虚拟内存中的地址可以映射到内存的任何地方,就它而言,进程拥有无限的内存。

    【讨论】:

    • 无限到VM空间的极限,对于32位进程来说真的没有那么大了。
    • 好的,操作系统如何执行正常的汇编指令来寻址不同的位置?这怎么可能?
    • @user35443 有一种叫做地址布局随机化的东西,每次加载时都会将内容加载到不同的地址。
    • 我的意思是 ASM 指令总是相同的。但是CPU怎么知道0x402000在物理内存中的位置。
    • 因为虚拟地址在专用硬件的帮助下被转换为物理内存
    猜你喜欢
    • 1970-01-01
    • 2020-05-05
    • 2016-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多