【问题标题】:Is it possible to access physical address 0?是否可以访问物理地址0?
【发布时间】:2014-12-31 09:07:40
【问题描述】:

在C/C++中,不允许访问地址0的数据。

但是,物理内存是从 0 开始编号的。而且,在 DOS 时代,中断向量表位于物理地址 0。第一个中断向量是被零除异常的处理程序。

我的问题是:

什么情况下允许访问物理地址0?

【问题讨论】:

  • 两种语言的标准都没有这样的限制。如果一个进程在一个不受保护的虚拟内存地址空间下运行,它就可以访问物理地址 0。保护本身由操作系统使用 MMU 实现。这一切都与 C 和 C++ 无关。
  • 很可能它将位于受操作系统保护的区域中;甚至可能是 ROM 的一部分。
  • 正如@SJuan76 指出的,这不是语言上的限制,而是物质上的限制
  • @barakmanos 说了什么。地址 0 在我的嵌入式系统上有效。任何老线程都可以写。
  • @MartinJames:就像我说的,如果一个进程在不受保护的虚拟内存地址空间下运行,它可以访问物理地址 0。如果您只运行一个没有虚拟内存管理的进程(许多嵌入式系统就是这种情况,有时甚至没有操作系统+多线程),那么显然您可以访问任何物理地址。其实这种场景下不需要逻辑地址。

标签: c++ c assembly operating-system x86


【解决方案1】:

C 标准不要求平台提供对任何特定物理内存位置的访问,无论是零还是其他。虽然 (char*)0x1234 访问物理位置​​ 0x1234 在许多嵌入式平台上很常见,但 C 标准中没有任何要求。

C 标准也不要求平台在尝试访问空指针时做任何特别的事情。因此,如果编译器编写者想要将空指针取消引用视为对物理位置 0 的访问,那么这种行为将符合要求。

对地址零的访问有意义且有用的编译器通常会将空指针访问解释为对地址零的访问。唯一的问题是对位置零的访问很有用但编译器编写者不知道的平台。这种情况通常只能通过检查编译器的文档来处理,以了解强制编译器将空指针视为任何其他地址的方法。

【讨论】:

    【解决方案2】:

    你的问题有点混乱。你问是否可以“访问物理地址为零”。在现代分页操作系统中,应用程序根本无法指定物理地址。物理地址只能通过内核模式访问。

    在虚拟内存系统中,通常不将虚拟内存的第一页映射到进程地址空间。因此,访问虚拟地址 0 会触发访问冲突。

    在这样的系统中,应用程序通常可以通过系统服务将首页映射到进程访问空间。即使该页面默认不存在,也可以由应用程序添加。

    答案是可以在内核模式下访问物理内存地址零,如果应用程序将该页面映射到内存(并且操作系统允许),则可以访问虚拟地址零。

    【讨论】:

      【解决方案3】:

      要访问物理地址为零,这取决于您正在谈论的平台。 该语言不知道底层寻址模型,它取决于操作系统。

      • 在裸机环境中,如果启用分页,您可以完全控制页表,如果未启用分页,则只需取消引用零。
      • 在某些 Unix 和 Linux 变体中,您可以使用 mmap 并可能还打开 /dev/mem 以获取逻辑地址非零但物理地址为零的非空指针,它可能需要一些访问权限。
      • 我不确定在 Windows 上。

      附言。其他答案似乎混淆了语言级指针和物理地址。

      【讨论】:

      • 我们这里不是在讨论取消引用空指针。我们谈论访问物理地址零,这可以通过将其映射到非空虚拟地址来实现。此外,OP的问题不仅限于C。
      • 是否可以在不使用分页的情况下访问 C/C++ 中的地址 0,并避免未定义的行为?
      • 简短的回答是否定的。如上所述,语言本身对底层地址模型一无所知,因此“在 C 或 C++ 中访问物理零”这个问题本身是没有意义的,或者至少是平台-具体的。如果没有分页,访问物理零的唯一方法是使用空指针,这是未定义的行为 - 它可能有效,也可能无效。
      • OUOH,还有另一种极端情况,您可以在不分页的情况下访问系统上的物理零 - 在古老的 8086 机器上,它在 1MB / A20 上进行内存包装。
      【解决方案4】:

      一般virtual memory中的address space由operating system管理。

      独立的 C(或 C++)实现当然可以让您以 实现特定的方式取消引用 (void*)0。但要小心undefined behavior。

      C 和 C++ 标准对 NULL 指针非常小心(C++11 添加了 nullptr 关键字有几个很好的原因)。

      允许 C 编译器(至少是托管实现)假设在成功取消引用后指针不为空。 GCC 中的一些优化正在这样做。

      大多数托管的 C 或 C++ 实现都有一个空指针,它是一个全零位的字,但这不是标准所要求的(但是,它很常见;它有助于编译器和 libc)。 但是,实际上,很多软件都假设 NULL 由全零位表示(理论上这是一个错误)。

      我不知道 NULL 不是全零位的 C 实现,但这不是必需的。但是,编写这样的编译器会让人头疼。

      在某些操作系统上,应用程序可以更改其地址空间,例如在 POSIX 或 Linux 上使用 mmap(2)。

      如果你真的想要,你可以访问 C 中的地址 0,但你真的不应该这样做。

      【讨论】:

        【解决方案5】:

        在 C 或 C++ 中都没有规范允许您为指针分配特定的物理地址。因此,您关于“如何访问地址 0”的问题可以正式转换为“如何将 0 地址分配给指针”,没有答案。您根本无法将特定地址分配给 C/C++ 中的指针。

        但是你可以通过整数到指针的转换来达到这个效果:-

        uintptr_t null_address = 0;
        void *ptr = (void *) null_address;
        

        【讨论】:

          【解决方案6】:

          在C/C++中,不允许访问地址0。

          可以,只要那里有可寻址的内存即可。在大多数平台上,不会有。

          什么情况下允许访问物理地址0?

          您可以访问任何映射到虚拟内存的物理地址。如果那里有任何敏感的东西,那么操作系统可能不会在用户代码中允许这样做。在内核中,只需设置页表以包含该地址。

          【讨论】:

            猜你喜欢
            • 2019-06-16
            • 2021-10-28
            • 2012-10-27
            • 1970-01-01
            • 2018-06-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-19
            相关资源
            最近更新 更多