为什么此.NET IL null检查无法按预期工作?

时间:2016-08-02 15:42:42

标签: .net cil

我正在编写一些自定义IL并需要等同于return SomeStaticField != null;的东西。这是我的自然结论:

volatile.ldsfld ...SomeStaticField //volatile is needed here for unrelated reasons
ldnull
ceq
not
ret

但是,这似乎不起作用。我确认SomeStaticField为null,但是这个函数最终会返回true。我知道C#使用分支来构建这样的构造,我也可以使用它,但它让我感到困惑的是为什么这不会有预期的行为

一个完整且可验证的示例(作为库):

.assembly extern /*23000001*/ mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly 'BareMetal'
{
  .custom instance void class [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::'.ctor'() =  (
                01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01       ) // ceptionThrows.

  .hash algorithm 0x00008004
  .ver  1:0:0:0
}
.module BareMetal.dll 


.namespace Earlz.BareMetal
{
  .class public auto ansi abstract sealed beforefieldinit BareMetal
        extends [mscorlib]System.Object
  {
    .method public static hidebysig
           default bool FooTest ()  cil managed
    {
        .maxstack 2
        ldnull
        ldnull
        ceq
        not
        ret
    }

  }
}

1 个答案:

答案 0 :(得分:6)

not计算其操作数的按位补码:~1-2,其为非零,为真。否定布尔值的规范方法是ldc.i4.0 ; ceq

并且,正如@HansPassant指出的那样,直接进行!= null比较的规范方法是cgt.un - 当解释为无符号值时,所有有效引用都“大于零”。 ECMA-335,第I.12.1.5节:

明确记录了这种比较是安全的
  

特别是,对象引用可以是:

     

...

     
      
  1. 创建为空引用(ldnull
  2.         

    ...

         

    托管指针有几个额外的基本操作。

         

    ...

         
        
    1. 基于两个托管指针(bge.unbge.un.sbgt.unbgt.un.sble.un的无符号比较和条件分支,   ble.un.sblt.unblt.un.scgt.unclt.un)。
    2.