gpt4 book ai didi

assembly - VA(虚拟地址)和 RVA(相对虚拟地址)

转载 作者:行者123 更新时间:2023-12-01 22:29:19 29 4
gpt4 key购买 nike

A file that is given as input to the linker is called Object File. The linker produces an Image file, which in turn is used as input by the loader.



来自“ Microsoft Portable Executable and Common Object File Format Specification ”的简介

RVA (relative virtual address). In an image file, the address of an item after it is loaded into memory, with the base address of the image file subtracted from it. The RVA of an item almost always differs from its position within the file on disk (file pointer).

In an object file, an RVA is less meaningful because memory locations are not assigned. In this case, an RVA would be an address within a section (described later in this table), to which a relocation is later applied during linking. For simplicity, a compiler should just set the first RVA in each section to zero.

VA (virtual address). Same as RVA, except that the base address of the image file is not subtracted. The address is called a “VA” because Windows creates a distinct VA space for each process, independent of physical memory. For almost all purposes, a VA should be considered just an address. A VA is not as predictable as an RVA because the loader might not load the image at its preferred location.



即使读了这篇文章,我仍然不明白。我有很多问题。任何人都可以用实际的方式解释它。请遵守 Object File 的术语& Image File就像声明的那样。

我所知道的关于地址的所有信息是
  • 无论是在目标文件中还是在图像文件中,我们都不知道确切的内存位置,因此,
  • 汇编器在生成目标文件时计算相对于部分的地址 .data & .text (对于函数名称)。
  • 链接器以多个目标文件作为输入生成一个 Image 文件。在生成时,它首先合并每个目标文件的所有部分,并在合并时再次重新计算相对于每个部分的地址偏移量。而且,没有什么比全局偏移更合适的了。

  • 如果我所知道的有什么不对的地方,请纠正我。

    编辑:

    在阅读了 Francis 给出的答案后,我很清楚物理地址、VA 和 RVA 是什么以及它们之间的关系是什么。

    所有变量和方法的 RVA 必须在重定位期间由链接器计算。所以, (方法/变量的 RVA 值)==(它从文件开头的偏移量) ?一定是真的。但令人惊讶的是,它不是。为什么这样?

    我通过使用 PEView 检查了这一点在 c:\WINDOWS\system32\kernel32.dll并发现:
  • RVA 和 FileOffset 直到节的开头都是相同的。(.text 是这个 dll 中的第一节)。
  • 从开始.text通过 .data , .rsrc直到最后一部分的最后一个字节( .reloc )RVA 和 FileOffset 是不同的。并且第一部分的第一个字节的 RVA 是“始终”显示为 0x1000
  • 有趣的是每个部分的字节在 FileOffset 中是连续的。我的意思是另一个部分从一个部分的最后一个字节的下一个字节开始。但是,如果我在 RVA 中看到相同的东西,那么这部分的最后一个字节的 RVA 和下一部分的第一个字节之间存在巨大的差距。

  • 我猜:
  • 全部,数据的字节数
    在第一个之前( .text 在这里)
    部分“未”实际加载
    进入进程的 VA 空间,这些
    字节数据仅用于
    找到并描述这些部分。
    它们可以被称为“元部分
    数据”。

    由于它们未加载到 VA
    过程空间。的使用
    术语 RVA 也毫无意义,这是
    原因RVA == FileOffset对于这些字节。
  • 自从,
  • RVA 术语仅对实际加载的那些字节有效
    进入VA空间。
  • .text 的字节数, .data , .rsrc , .reloc是这样的字节。
  • 而不是从 RVA 0x00000 开始PEView 软件正在启动
    它来自 0x1000 .
  • 我不明白为什么第三次观察。我无法解释。
  • 最佳答案

    大多数 Windows 进程 (*.exe) 加载在(用户模式)内存地址 0x00400000 中,这就是我们所说的“虚拟地址”(VA)——因为它们只对每个进程可见,并且会被转换为不同的物理地址操作系统(内核/驱动层可见)。

    例如,一个可能的物理内存地址(CPU 可见):

    0x00300000 on physical memory has process A's main
    0x00500000 on physical memory has process B's main

    操作系统可能有一个映射表:
    process A's 0x00400000 (VA) = physical address 0x00300000
    process B's 0x00400000 (VA) = physical address 0x00500000

    然后,当您尝试在进程 A 中读取 0x004000000 时,您将获得位于物理内存 0x00300000 上的内容。

    关于 RVA,它只是为了简化搬迁而设计的。当加载可重定位模块(例如,DLL)时,系统将尝试将其滑过进程内存空间。所以在文件布局中它放了一个“相对”地址来帮助计算。

    例如,DLL C 可能具有以下地址:
     RVA 0x00001000 DLL C's main entry

    当在基地址 0x10000000 处加载到进程 A 时,C 的主条目变为
     VA = 0x10000000 + 0x00001000 = 0x10001000
    (if process A's VA 0x10000000 mapped to physical address was 0x30000000, then
    C's main entry will be 0x30001000 for physical address).

    当被加载到基地址 0x32000000 处的进程 B 时,C 的主入口变为
     VA = 0x32000000 + 0x00001000 = 0x32001000
    (if process B's VA 0x32000000 mapped to physical address was 0x50000000, then
    C's main entry will be 0x50001000 for physical address).

    通常图像文件中的 RVA 在加载到内存时是相对于进程基地址的,但有些 RVA 可能与图像或目标文件中的“节”起始地址有关(您必须查看 PE 格式规范以了解详细信息)。无论哪个,RVA 都是相对于“某些”基础 VA 而言的。

    总结一下,
  • 物理内存地址是 CPU 看到的
  • 虚拟地址 (VA) 相对于物理地址,每个进程(由操作系统管理)
  • RVA 相对于 VA(文件库或节库),每个文件(由链接器和加载器管理)

  • (编辑)关于爪的新问题:

    方法/变量的 RVA 值并不总是与文件开头的偏移量。它们通常与某些 VA 相关,这可能是默认加载基址或段基 VA - 这就是为什么我说您必须检查 PE format spec详情。

    您的工具 PEView 试图显示每个字节的 RVA 以加载基地址。由于部分从不同的基数开始,因此在交叉部分时 RVA 可能会变得不同。

    关于你的猜测,它们非常接近正确答案:
  • 通常我们不会在节之前讨论“RVA”,但 PE header 仍会加载到节 header 结束。不会加载节标题和节正文(如果有)之间的间隙。您可以通过调试器进行检查。此外,当部分之间存在一些间隙时,它们可能不会被加载。
  • 正如我所说,RVA 只是“相对于某些 VA”,不管它是什么 VA(虽然在谈论 PE 时,VA 通常指的是负载基址)。当您阅读 t PE 格式规范时,您可能会发现一些“RVA”,它与某些特殊地址(如资源起始地址)相关。来自 0x1000 的 PEView 列表 RVA 是因为该部分从 0x1000 开始。为什么是 0x1000?因为链接器为 PE 头留下了 0x1000 个字节,所以 RVA 从 0x1000 开始。
  • 您错过的是 PE 加载阶段中“部分”的概念。 PE 可能包含多个“段”,每个段映射到一个新的起始 VA 地址。例如,这是从win7 kernel32.dll dump出来的:
    #  Name   VirtSize RVA      PhysSize Offset
    1 .text 000C44C1 00001000 000C4600 00000800
    2 .data 00000FEC 000C6000 00000E00 000C4E00
    3 .rsrc 00000520 000C7000 00000600 000C5C00
    4 .reloc 0000B098 000C8000 0000B200 000C6200

    有一个不可见的“0 header RVA=0000, SIZE=1000”,它强制 .text 从 RVA 1000 开始。当加载到内存(即 VA)时,这些部分应该是连续的,因此它们的 RVA 是连续的。但是,由于内存是按页面分配的,因此它将是页面大小的倍数(4096=0x1000 字节)。这就是为什么#2 部分从 1000 + C5000 = C6000 开始(C5000 来自 C44C1)。

    为了提供内存映射,这些部分仍然必须按某种大小对齐(文件对齐大小 - 由链接器决定。在我上面的示例中,它是 0x200=512 字节),它控制着 PhysSize 字段。 Offset 的意思是“偏移到物理 PE 文件的开头”。

    所以头占用文件的 0x800 字节(映射到内存时为 0x1000),这是第 #1 节的偏移量。然后通过对齐它的数据(c44c1 字节),我们得到 physsize C4600。 C4600+800 = C4E00,正好是第二段的偏移量。

    好的,这与整个 PE 加载内容有关,因此可能有点难以理解...

  • (编辑)让我再做一个新的简单总结。
  • DLL/EXE(PE 格式)文件中的“RVA”通常与“加载内存基地址”相关(但并非总是如此——你必须阅读规范)
  • PE 格式包含一个“节”映射结构,用于将物理文件内容映射到内存中。因此,RVA 并不是真正与文件偏移量相关。
  • 要计算某个字节的 RVA,您必须在该部分中找到它的偏移量并添加部分基数。
  • 关于assembly - VA(虚拟地址)和 RVA(相对虚拟地址),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2170843/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com