使编译的二进制文件以本机速度完美运行,而无需从另一个系统上的源代码重新编译?

时间:2011-01-09 07:17:59

标签: compiler-construction constraints virtualization native aot

我知道很多人,乍一看这个问题,可能会立即大喊大叫,但不,我知道Java的特质。请允许我先说明我的问题。

通常,当我们希望程序在系统上以本机速度运行时,无论是Windows,Mac OS X还是Linux,我们都需要从源代码编译。如果要在系统中运行其他系统的程序,则需要使用虚拟机或模拟器。虽然这些工具允许您在非本机操作系统上使用所需的程序,但它们有时会出现性能和故障问题。

我们还有一个名为" JIT Compiler"的新编译器,编译器在执行之前将字节码程序解析为本机机器语言。使用JIT Compiler,性能可能会有很大提升,但性能仍然与在本机系统上运行它的性能不同。

Linux上的另一个程序WINE也是在Linux系统上运行Windows程序的好工具。我已经尝试过运行Team Fortress 2,并试着尝试一些设置。在1280 x 1024的中高设置下,我在Windows上获得了~40 fps。在Linux上,我需要将所有内容都调低至1280 x 1024以获得~40 fps。但有两件值得注意的事情:

  1. 无论我将其设置为低还是高,多边形模型设置似乎都不会影响帧速率。
  2. 当有后处理效果或某些特殊效果需要操纵当前帧的绘制像素时,帧速率将降至10-20 fps。
  3. 从这一点来看,我可以看到普通的多边形渲染很好,但是当需要使用图形卡来处理作业的新渲染方法时,它会慢下来爬行。

    无论如何,这个问题相当理论化。有什么我们可以做的吗?我看到WINE可以运行STEAM和Team Fortress 2.虽然存在缺陷,但它们可以在较低的设置下运行。或许,我也应该问," 是否可以将系统上的整个程序翻译成另一个系统,而无需从源代码重新编译并获得原生速度?"我看到我们也有AOT编译器,是否可以将它用于这样的东西?或者有很多限制(例如DirectX调用或软件架构的差异)使得无法以本机速度运行的系统程序完美无缺?

2 个答案:

答案 0 :(得分:6)

在没有重新编译的情况下以本机速度在多个系统上运行相同编译代码体的第一步是选择一个处理器指令集并抛弃所有其他系统。如果选择Intel,则必须抛弃ARM,MIPS,PowerPC等,因为一个架构的本机机器代码指令对于其他处理器来说完全无法理解。

确定。因此,现在的任务是在本机速度下在多个系统(均使用相同的处理器体系结构)上运行相同的编译本机代码体,而无需重新编译。基本上,您希望在同一硬件上的不同操作系统下运行相同的代码。

如果硬件是相同的,唯一的区别是操作系统,那么简单的答案是肯定的,如果您可以编写代码而不需要调用操作系统,则可以执行此操作。没有内存分配。无控制台输出。没有文件I / O.没有网络I / O.没有什么好玩的。

此外,您的代码必须以代码不需要地址重定位修正的方式编写,因为每个操作系统都有不同的方式来表示可重定位代码。一种方法是将代码安排在磁盘上,就像在内存中一样,包括保留用于可写数据的空间(全局变量,堆栈和堆)。然后,您需要做的就是运行代码,将文件字节复制到预定义基址的内存中,然后跳转到起始地址。

MSDOS .com可执行文件格式至少自1981年以来一直在这样做,并且在此之前很久就已经开始使用CP / M.

然而,MSDOS当时没有今天的病毒扫描程序可以应对。当主机操作系统以外的任何人将文件数据加载到内存并尝试执行该内存时,病毒扫描程序会非常兴奋。因为,你知道,这正是病毒的作用。

由于每个操作系统都有自己的可执行文件格式,因此您还需要弄清楚如何在所有这些不同的操作系统上将“无瑕疵”的本机代码块存入内存。您至少需要为每个要运行本机代码块的操作系统编译一个程序加载器。当您为要定位的每个OS编写程序加载程序时,您还可以定义自己的文件I / O函数映射到OS本机等效项,以便您的本机代码块可以在任何系统上执行文件I / O.同样适用于控制台I / O或图形输出。

哦等等 - 这正是WINE所做的。

这也是为什么你在WINE中看到的帧速率比主机操作系统中的相同操作低得多的原因 - WINE正在将Win32 GDI图形调用转换为本机主机OS(Linux - > XWindows)提供的内容,以及如果没有精确的函数匹配或者存在操作语义不匹配(通常情况下),WINE必须自己实现所有功能,有时需要付出很大的代价。

但鉴于IDE驱动器,USB设备和BIOS功能等标准化硬件无处不在,您可能不需要将自己的便携式API映射到操作系统内置的任何问题。只需编写一个用于向IDE设备执行文件I / O的小代码,使用VESA BIOS功能进行图形输出。如果您稍微抽象一下代码,您可以支持多种硬件,并根据您在运行时找到的硬件选择适当的函数指针。

然后,您可以在任何系统(使用一个特定的处理器体系结构)上以原生速度真正运行本机代码块,而无需重新编译。

哦等等 - 你刚刚编写了自己的操作系统。 ;>

答案 1 :(得分:4)

是的,技术上可以将为一个处理器体系结构和操作系统编写的二进制可执行程序转换为将在另一个处理器和操作系统上运行的二进制可执行程序。这也是一种不圣洁的工作。

“本机代码执行速度”术语存在问题。您可以将程序编译为本机代码并禁用优化,结果代码将是以“本机代码执行速度”运行的本机可执行代码,但它可能比启用优化编译的相同源代码运行得慢。两者都运行“本机代码执行速度”,但它们运行不同数量和质量的机器代码以实现相同的核心算法。

机器指令比高级源编程语言更原始。将源代码编译成机器代码时,会丢失大量信息。例如,数据类型通常由编译器减少到少数几个机器基元 - 指针,整数,浮点数。字符串是指向内存的指针。 char是整数。对象实例是指针。

当您将一个机器指令集翻译成另一个机器指令集时,您将受到妨碍,因为您没有像源代码编译器那样有关数据的信息。从源代码编译,编译器可以看到数据中的关系和优化,仅通过单独查看机器代码就很难发现。

故事时间:Digital Equipment Corporation创建了一个名为FX!32的系统,该系统采用本机编译的Win32 Intel x86可执行文件,对其进行反编译,并将逻辑转换为运行Windows NT AXP的本机Alpha AXP处理器指令。在这种情况下,操作系统至少是从同一块布上剪下来的,但是一个是32位,另一个是64位,而在机器代码级别,它们的调用约定完全不同。尽管如此,它仍然有效,而且效果非常好。由于硬件方面的差异,在AXP上运行的英特尔x86应用程序最终运行速度可能比在英特尔硬件上运行的相同应用程序运行得更快。 (FX!32在英特尔应用程序运行几次后使用分析来重新优化AXP代码,因此每次运行应用程序时,性能通常都很糟糕但有所改善)

然而,即使所有内容都在执行本机AXP指令,FX!32翻译的应用程序也从未像获取源代码那样快速运行并专门为AXP指令集重新编译它。 FX!32翻译的原生AXP指令流由于必须完全代表原始Intel x86指令的语义而变得庞大,即使(看不见的)更高级算法不需要那些语义的所有方面。

在进行机器指令翻译的机器指令时,您可以看到/听到交响乐中的每个音符,但是您可能无法选择定义旋律的音符。