1

メソッドを発行するために IL の解析を試しています。各文字列が IL 命令である string[] 内のメソッドの IL コードを取得しました。この配列をループして、ILGenerator を使用して OpCode を追加しています。

        foreach (string ins in instructions) //string representations of IL          
        {
            string opCode = ins.Split(':').ElementAt(1);

            // other conditions omitted

            if (opCode.Contains("br.s"))
            {
                Label targetInstruction = ilGenerator.DefineLabel();

                ilGenerator.MarkLabel(targetInstruction);

                ilGenerator.Emit(OpCodes.Br_S, targetInstruction); 
            }

再現する必要がある IL は次のとおりです。

Source IL:
IL_0000: nop
IL_0001: ldstr "Hello, World!"
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret

そして、ここに私が出力として得ているものがあります:

Target IL:
IL_0000: nop
IL_0001: ldstr "Hello, World!"
IL_0006: stloc.0
IL_0007: br.s IL_0007   // this is wrong -- needs to point to IL_0009
IL_0009: ldloc.0
IL_000a: ret

ご覧のとおり、br.s 呼び出しはそれ自体を指しているため、もちろん無限ループが発生します。ソースのように次の命令を指すようにするにはどうすればよいですか? これは Reflection.Emit.Label の使用に関係していますが、どのように機能するかはわかりません。

編集ちなみに、上記のILはこの単純な方法のためのものであり、

    public string HelloWorld()
    {
            return "Hello, World!";
    }
4

3 に答える 3

5

このコード:

ilGenerator.MarkLabel(targetInstruction);
ilGenerator.Emit(OpCodes.Br_S, targetInstruction); 

「ここにラベルを付けてください」と明確に言ってから、ラベルを付けた場所に指示を追加します。

これがあなたの望んでいるものではないなら、なぜあなたはそれをしているのですか?

MarkLabel は、現在の位置、つまり出力する次の命令の位置をラベルのターゲットとしてマークします。

この場合、「必要なもの」を取得するには、これらの 2 行を逆にして、ラベルをマークする前に分岐命令を出力します。

その分岐命令のポイントがわからないので、「あなたが望むもの」を引用符で囲みました。マシンは自動的に次の命令に喜んで「移動」します。これを行うために「次の命令への分岐」命令を追加する必要はありません。

于 2011-07-20T18:49:04.073 に答える
4

ジャンプ先ilGenerator.MarkLabel()のオペコードを発行する直前に呼び出しを行う必要があります。分岐の前に配置しているため、それ自体に分岐し、効果的に無限ループが作成されます。しかし、ラッセが言うように、IL を正しく発行すればノーオペレーションになります。

興味深いことに、メソッド全体は簡単に次のようになります。

ldstr "Hello, World!"
ret

元のコードを発行したコンパイラは、その作成者を LARTed にする必要があります。

于 2011-07-20T18:47:06.510 に答える
0

MarkLabel()ILGeneratorでメソッドを呼び出して分岐点をマークし、続いEmit(OpCodes.Br_S, [label])てその点に分岐することができます。

Hello World メソッドの IL 命令をスパイするために使用した API はすべてデバッグ モードで実行されたと思います。追加された nop 命令と分岐命令が追加され、デバッガーがすべてのステップを確実にカバーできるようにするためです。

DynamicMethod では、デバッガーをアタッチする必要はありません。また、プラットフォームによっては、リリース モードで追加の命令を使用して実行すると、InvalidProgramException が発生する可能性があります。

「Hello World」メソッドに必要な命令は 2 つだけです (非常に直感的です)。

Ldstr "Hello, World!"
Ret
于 2016-04-21T02:22:44.567 に答える