我正在玩MSIL反编译器 - ILDASM,我试图反编译一个简单的.NET方法。
操作码看起来像这样:
.method private hidebysig static int32 Add(int32 a,
int32 b) cil managed
{
// Code size 18 (0x12)
.maxstack 2
.locals init ([0] int32 c,
[1] int32 d,
[2] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.5
IL_0003: add
IL_0004: stloc.0
IL_0005: ldarg.1
IL_0006: ldc.i4.s 10
IL_0008: add
IL_0009: stloc.1
IL_000a: ldloc.0
IL_000b: ldloc.1
IL_000c: add
IL_000d: stloc.2
IL_000e: br.s IL_0010
IL_0010: ldloc.2
IL_0011: ret
}
我想知道的是 - 这些操作码是原子的吗?即在抢先式调度内核中,单个操作码在完成执行之前是否有可能被抢占?这里的操作码可以很容易地以1:1的方式映射到asm指令,因为它们具有用于加载,存储,添加等的单独操作码。
但是在更复杂的操作码的情况下呢?比如“call”,当操作数是一个方法引用标记时,应首先遵循该方法来解析该方法然后调用?那是原子吗?
答案 0 :(得分:14)
不,并非所有操作码都是原子的。例如,如果对大于本机指针大小的值类型使用stloc
或ldloc
,那么不能保证它是原子的。
ECMA 335的第12.6.6节保证了这么多:
符合要求的CLI应保证在对位置进行所有写访问时,对正确对齐的内存位置的读写访问权限不大于本机字大小(native int类型的大小)是原子的(参见§12.6.2)大小相同。原子写入除了写入之外不得改变任何位。
...但是有一个注释:
[注意:当native int的大小为32位时,没有保证对8字节数据的原子访问,即使某些实现在数据在8字节边界上对齐时可能执行原子操作。结束说明]
这意味着任何存储或读取Int64
的操作码都不能保证在x86上是原子的,例如......
答案 1 :(得分:0)
我不认为IL指令定义了原子性。它是根据负载定义的,并存储在内存中。
关于装载和存储的原子性规则很复杂。它们与存储值的对齐和大小有关。
你的“呼叫”示例没有意义:它不访问内存。原子性的概念与调用指令无关。