13

私は現在、オペレーターとの新しい問題に直面しています。if ... else次のコードを使用して、C# でペアを使用する場合と同じ出力を作成したいと考えています。

var method = new DynamicMethod("dummy", null, Type.EmptyTypes);
var g = method.GetILGenerator();

g.Emit(OpCodes.Ldstr, "string");
g.Emit(OpCodes.Ldstr, "string");
g.Emit(OpCodes.Call, typeof(String).GetMethod("op_Equality", new Type[]{typeof(string), typeof(string)}));
g.Emit(OpCodes.Ldc_I4, 0);
g.Emit(OpCodes.Ceq);
g.Emit(OpCodes.Brtrue_S, );

var action = (Action)method.CreateDelegate(typeof(Action));
action();

Console.Read();

私の質問は次のとおりです。

  1. 分岐オペコードのパラメーターとして渡す命令のアドレスを取得するにはどうすればよいですか?
  2. BRBR_SBrtrueBrtrue_SBrfalseおよびBrfalse_S類似の命令に違いはありますか?

ありがとう。

4

3 に答える 3

10
  1. DefineLabelと メソッドの組み合わせを使用してMarkLabel、ブランチのターゲットの場所を決定できます。そのためには、必要なラベルを宣言します-とのようなもの equalですnotequal。次に、ラベルが存在する必要があるIL内のスポットをマークできます。これが完了すると、分岐命令のターゲットをこのラベルに設定できます。

    // Define labels
    Label equal = g.DefineLabel();
    Label notEqual = g.DefineLabel();
    Label endOfMethod = g.DefineLabel();
    // your logic here
    g.Emit(OpCodes.Brtrue_S, equal);
    g.MarkLabel(equal);
    // some code if they are equal
    g.MarkLabel(notEqual);
    // some code if they are not equal
    g.MarkLabel(endOfMethod); // this marks the return point
    g.Emit(OpCodes.Ret);
    
  2. 、、、およびそれらの対応物の違いはBr、 ジャンプの長さです。は短縮形を示します。ターゲット命令は、次の命令からの1バイトの符号付きオフセットです。標準(非短縮)形式では、ターゲットは4バイトのオフセットで表されます。BrtrueBrfalse_S_S

于 2012-06-21T13:38:37.307 に答える
8

ILGenerator.ILOffset必要に応じて、ILストリームの現在のオフセットを提供します。goricが提案したように、DefineLabelandも使用できます。MarkLabel

brtrue.sとの唯一の違いbrtruebrtrue.s、の短いバージョンですbrtruebrtrue4バイトのオフセットをbrtrue.s使用し、1バイトのオフセットを使用します。brfalse同じことがand brfalse.s(およびbr/ )にも当てはまりますbr.s

IL命令の短いバージョンはこれらだけではありません。整数をロードするためのldc.i4.0-のような他の短い命令もあります。ldc.i4.8これらは主に小さなバイナリを生成するのに役立ちますが、それ以外に大きな違いはないと思います。

于 2012-06-21T13:38:39.597 に答える
4

これは私にとって新しいことですが、少し検索すると、電話でアドレスを取得できるようです

Label targetInstruction = g.DefineLabel();

事前のある時点で (たとえば、最初のEmit?)、その後

g.MarkLabel(targetInstruction);

分岐先の行を発行する直前. 次に、これはオペコードLabelへの引数です。Br____

BrBrtrueBrfalseの違いは、Br は常に分岐し、他の 2 つはスタックから値をポップし、それぞれ true または false の場合にのみ分岐することです。(そうです、大きな違いがあります!) _S は「短い形式」を意味しますが、これが何を意味するのかわかりません。

于 2012-06-21T13:39:51.093 に答える