【问题标题】:how come an x64 OS can run a code compiled for x86 machine为什么 x64 操作系统可以运行为 x86 机器编译的代码
【发布时间】:2012-08-02 12:12:45
【问题描述】:

基本上,我想知道的是为什么 x86-64 操作系统可以运行为 x86 机器编译的代码。我知道当第一个 x64 系统被引入时,这不是它们中的任何一个的特性。在那之后,他们以某种方式设法做到了。

请注意,我知道 x86 汇编语言是 x86-64 汇编语言的子集,而 ISA 的设计方式使其可以支持向后兼容性。但是这里让我感到困惑的是堆栈调用约定。这些约定因架构而异。例如,在 x86 中,为了备份帧指针,进程会在它指向堆栈(RAM)的位置推送,并在完成后弹出。另一方面,在 x86-64 中,进程根本不需要更新帧指针,因为所有引用都是通过堆栈指针给出的。其次,在 x86 架构中,函数的参数是通过 x86-64 中的堆栈传递的,而寄存器则用于此目的。

也许 x86-64 和 x64 体系结构的堆栈调用约定之间的这种差异可能不会影响程序堆栈的增长方式,只要不同时使用不同的约定,这主要是因为 x32 函数被其他函数调用x32 和 x64 相同。但是,在某一时刻,一个函数(可能是一个系统函数)将调用一个函数,该函数的代码是为带有一些参数的 x86-64 机器编译的,此时,我很好奇操作系统(或其他一些控制单元)如何处理让这个功能工作。

提前致谢。

【问题讨论】:

    标签: 64-bit x86-64


    【解决方案1】:

    i386/x86-64 架构的部分设计方式是CS 和其他段寄存器引用GDT 中的条目。 GDT条目除了base和limit之外还有一些特殊的位描述当前运行任务的操作模式和权限级别。

    如果 CS 寄存器引用 32 位 code segment,处理器将运行在本质上是 i386 兼容模式。同样,64 位代码需要一个 64 位代码段。

    所以,把这一切放在一起。

    当操作系统要运行一个 32 位任务时,在任务切换到它的过程中,它会将一个值加载到 CS 中,该值引用一个 32 位代码段。中断处理程序也有与之关联的段寄存器,因此当发生系统调用或发生中断时,处理程序将切换回操作系统的 64 位代码段,(允许 64 位操作系统代码正确运行)和操作系统然后可以完成工作并继续安排新任务。

    作为关于调用约定的跟进。 i386 或 x86-64 要求使用帧指针。代码可以随意做。事实上,许多编译器(gcc、clang、VS)都提供了在没有帧指针的情况下编译 32 位代码的能力。 重要的是调用约定的实现是一致的。如果所有代码都希望参数在堆栈上传递,那很好,但被调用的代码最好同意这一点。同样,通过寄存器传递也可以,只是每个人都必须同意(至少在库接口级别,内部函数通常可以为所欲为)。

    除此之外,请记住,两者之间的差异并不是真正的问题,因为每个进程都有自己的私有内存视图。附带的后果是 32 位应用程序无法加载 64 位 dll,而 64 位应用程序无法加载 32 位 dll,因为进程要么具有 32 位代码段,要么具有 64 位代码部分。不能两者兼有。

    【讨论】:

    • 感谢您提供全面而清晰的回答。 x86 指令(使用 32 位寄存器 - eax、ebx 等)可以在 64 位进程中执行吗?例如:在指令mov eax, [ecx]中,ecx的值将被视为32位地址,但由于进程是64位的,我认为它可以引用64位内存中的地址-仅限空间。理论上,这条指令真的应该在 64 位进程中执行吗?
    • @Bliss,是的,所有 32 位寄存器都可以在 64 位模式下完全访问。
    • 至于 32 位寄存器,你当然需要小心,因为地址会从零扩展到 64 位,你不是想用 4GB 标记来引用地址32 位地址。不过,使用相对寻址模式在很大程度上使这不是问题。
    • 非常感谢。所以基本上,如果我理解正确,32 位汇编代码原则上可以在 64 位 CPU 上执行,除非它引用位于 64 位地址空间中的程序数据(例如变量)(即 64 位指针)。 小代码模型是否可以在 C++ 中尽可能应用于(64 位)C# 程序(使用 Visual Studio 2010)?
    【解决方案2】:

    处理器进入传统模式,但这要求当时执行的所有内容都是 32 位代码。此切换由操作系统处理。

    Windows:它使用WoW64。 WoW64负责改变处理器模式,它还提供了兼容的dll和注册表功能。

    Linux : 直到最近,Linux 曾经(如 Windows)在开始执行 32 位代码时转向以传统模式运行处理器,您需要安装所有 32 位 glibc 库,如果它试图与64位代码。现在正在实施X32 ABI,它应该使一切运行更顺畅,并允许 32 位应用程序访问 x64 功能,如增加编号。的寄存器。 See this article on the x32 abi

    PS : 我对事情的细节不是很确定,但它应该给你一个开始。

    此外,这个答案与 Evan Teran 的答案相结合,可能会大致了解正在发生的一切。

    【讨论】:

    • WOW64 更像是解决方案的 API 层部分(它是 32 位 dll,可以安全地转接到 64 位系统调用)。它并没有真正解决 CPU 级别的任何问题。 Hense 它缺少“Windows 64 上的 Windows”。澄清一点,我不会把它准确地称为“虚拟化”,更多的是“抽象”
    • 经过更多研究后更改了我的答案。你是对的,称它为抽象层会更好。
    猜你喜欢
    • 2012-05-28
    • 2011-01-08
    • 2015-05-06
    • 2011-07-03
    • 2015-09-05
    • 2020-12-29
    • 1970-01-01
    • 2011-12-03
    • 2011-10-16
    相关资源
    最近更新 更多