0

我正在开发一个系统,该系统在开发时将一整套 .NET 程序集“烘焙”为本机代码。理想情况下,它会直接输出机器语言,但为了省去处理寄存器着色、针对不同目标平台的不同机器代码等的麻烦,我选择让它输出 C 代码,然后使用现有的编译器将其编译为 ML。

这引入的一个问题是整数数学运算的溢出检查不能在 C 代码中有效地执行。某些 CIL 指令——即带有.ovf后缀的指令,明确地检查溢出。 另一个问题的众多答案提出了在 C 中进行此类检查的各种技术,但与 JIT 编译器可能输出的机器代码(例如,jointo在英特尔上)相比,它们的性能都非常差。

考虑到应用程序对性能非常关键,很容易忽略.ovf这些指令并发出与未检查变体相同的 C 代码。根据 ECMA-335 严格来说,这当然会破坏我的 CLI 实现,但我想知道它是否真的会在实践中被破坏。

我的印象是这些检查主要用于程序调试。在使用我的 CLI 的上下文中,该程序已经调试过了,并且它没有控制核弹头(反正不是真正的核弹头。)

该系统主要用于我们自己的代码,这些代码都不依赖于溢出检查的正确性。(据此,将是一种糟糕的形式。)我关心的主要是我们可能链接到的 .NET 类库,我的系统当然也必须处理这些类库。

在我预见到必须链接的所有代码中,我主要关心的是 Mono 附带的 BCL。我们正在考虑使用该 BCL,因为它已经是现成的并且获得了自由许可。但是,当我从 Mono 对 System.dll 进行 IL 转储时,我发现它充满了.ovf指令(其中许多是conv.ovf,可以在 C 中像在 ML 中一样高效地实现,但有些是在算术上。)

Mono 的 BCL 实际上是否会依赖于任何这些检查的正确性,或者它们只是对于已经被认为是健全的代码可以安全地忽略的健全性检查?(我期待后者,但我想我会问,以防其他人知道得更好。)

4

1 回答 1

2

我认为将其转换为 C 的主要问题是 CIL 本质上是一种比 C 更低级别的语言,并且通常很难“爬升”语言级别。您的示例表明,在 x86 中检查溢出是微不足道的,但在 C 中实际上非常困难。

关于忽略 Mono BCL 中的溢出检查,最重要的问题是

如果不需要检查,为什么要使用它们?

Mono BCL 是一个相当成熟的库,因此期望它由知道自己在做什么的人编写是明智的;因此,如果您通过删除溢出检查来修改代码,代码可能看起来工作得很好,但请记住,溢出情况应该是异常而不是规则。此外,虽然以前溢出会立即抛出异常,但现在它会通过关于它可能会或可能不会导致更大问题的“坏数据”。

简而言之,删除溢出检查可能意味着大部分时间大部分代码都可以工作,但不再有任何保证。这意味着除非您非常彻底地检查每个可能的代码路径或用测试用例覆盖所有代码,否则您会因避免这些检查而面临巨大的风险。

于 2013-08-18T21:22:19.030 回答