MSIL 和 LLVM 位码有什么区别?

What are the differences between MSIL and LLVM bitcode?

我是 .Net 的新手,我想先了解基础知识。 MSIL 和 LLVM 位码有什么区别?

LLVM 位码和 MSIL 都是 intermediate languages。本质上,它们是通用汇编代码语言:不像大多数源语言(例如 Swift、C#)那样高级,但也不像真正的汇编语言(例如 ARM、x86)那样低级。这两种语言之间存在许多技术实现差异,但大多数开发人员不需要了解这些细节*。他们只需要了解它们在各自平台的分发模型中的使用方式。


LLVM 位码格式是 the intermediate representation code used within the LLVM compiler 的序列化版本。编译器的"front end"将源语言(如Swift)翻译成LLVM bitcode,然后编译器的"back end"将bitcode翻译成目标指令集(如ARM机代码)。 (注意:此答案的先前版本暗示 LLVM 位码与处理器无关。事实并非如此,因为源语言取决于目标处理器。)

Apple 允许 iOS 开发人员提交他们的应用程序作为完全编译的 ARM 代码 or as LLVM bitcode,后者:

[...] will allow Apple to re-optimize your app binary in the future without the need to submit a new version of your app to the store.

本质上,您 运行 开发环境中的 LLVM 前端,将位码传递给 Apple,Apple 运行 在他们的服务器上设置 LLVM 后端。这个过程被称为提前(AOT)编译the Wikipedia article对于非位码情况是否也是AOT或者是否只是"standard"编译)。

但是无论您是否使用 bitcode,iOS 最终用户始终会以 ARM 机器代码的形式获取应用程序。


.NET 中的情况有些不同。大多数 .NET 代码都编译为 MSIL,打包在名为 assemblies 的文件中。最终用户设备上的 .NET 运行 时间加载和执行程序集,在 运行 时间将 MSIL 编译为设备处理器的机器代码。这称为 即时 (JIT) 编译

通常,MSIL 与处理器无关,因此大多数开发人员可以认为 .NET 应用程序也是与处理器无关的。但是,有多种方法可以在最终用户 运行 通过 JIT 将应用程序打包之前打包特定于处理器的代码:

  1. 一些工具,如 Native Image Generator and .NET Native,允许 AOT 编译。事实上,上传到 Microsoft Store 的通用 Windows 平台 (UWP) 应用程序是 AOT 编译的 - 您将应用程序的 MSIL 版本提交给 Microsoft,然后他们的服务器使用 .NET Native 为各种架构编译它 Windows10支.

  2. 也可以在程序集本身中包含本机代码;这些被称为 mixed assemblies.

  3. MSIL 本身可以是处理器特定的,如果源语言使用 "unsafe" 操作(例如,pointer math in C#)。

但这些通常是例外情况,而不是规则。通常,.NET 应用程序以 MSIL 分发,最终用户的设备是生成本机代码的地方。


总而言之:

  • LLVM 位码是特定于处理器的,但不像实际的机器代码那么低级。 Apple 允许 iOS 开发人员以位码形式提交应用程序,以便在可以引入优化时允许将来重新编译。最终用户 运行 的本机可执行文件。

  • MSIL 通常与处理器无关。最终用户通常 运行 使用这种与处理器无关的代码,而 .NET 在 运行 时将 MSIL 编译为本机代码。但是,在某些情况下,部分或全部应用程序可能是本机代码。


* 当然,如果您 对技术细节感兴趣,这里有标准for LLVM bitcode and for MSIL, under its ECMA name CIL。我对后者有一定的了解;粗略浏览前者后,最显着的技术差异是内存模型:LLVM 位码是基于寄存器的,MSIL/CIL 使用评估堆栈。