ひっそりと生きるプログラマのブログ

日頃気になった事なりを書き留めるブログです。関心ごとは多くもう少し更新頻度を上げたいところです。

PowerShellでILを使ってexeを作ってみる

たまにこういうコードを書かないと忘れるので少し書いてみます。
需要はありませんが、こんなことも出来るっていう参考になれば幸いです。

function Hello-World-Il() {
    $domain = [System.AppDomain]::CurrentDomain
    $assemblyName = New-Object System.Reflection.AssemblyName("Test")
    $directory = "c:\temp"
    $assemblyBuilder = $domain.DefineDynamicAssembly($assemblyName, [System.Reflection.Emit.AssemblyBuilderAccess]::RunAndSave, $directory)
    $moduleBuilder = $assemblyBuilder.DefineDynamicModule("sample.exe");
    $typeBuilder = $moduleBuilder.DefineType("Program", [System.Reflection.TypeAttributes]::Class);
    $methodBuilder = $typeBuilder.DefineMethod("Main", [System.Reflection.MethodAttributes]::Static);
    $write = [System.Console].GetMethod("WriteLine", [type[]]([string]))
    $readLine = [System.Console].GetMethod("ReadLine")
    $concat = [System.String].GetMethod("Concat",[type[]]([string],[string]))
    $il = $methodBuilder.GetILGenerator();
    $il.Emit([System.Reflection.Emit.OpCodes]::Nop);
    $a = $il.DeclareLocal([string])
    $il.Emit([System.Reflection.Emit.OpCodes]::Nop)
    $il.Emit([System.Reflection.Emit.OpCodes]::Ldstr, "文字を入力して下さい。")
    $il.Emit([System.Reflection.Emit.OpCodes]::Call, $write)
    $il.Emit([System.Reflection.Emit.OpCodes]::Nop)
    $il.Emit([System.Reflection.Emit.OpCodes]::Call, $readLine)
    $il.Emit([System.Reflection.Emit.OpCodes]::Stloc, $a)
    $il.Emit([System.Reflection.Emit.OpCodes]::Ldloc, $a)
    $il.Emit([System.Reflection.Emit.OpCodes]::Ldstr, "と入力しました。")
    $il.Emit([System.Reflection.Emit.OpCodes]::Call, $concat)
    $il.Emit([System.Reflection.Emit.OpCodes]::Call, $write)
    $il.Emit([System.Reflection.Emit.OpCodes]::Nop)
    $il.Emit([System.Reflection.Emit.OpCodes]::Call, $readLine)
    $il.Emit([System.Reflection.Emit.OpCodes]::Pop)
    $il.Emit([System.Reflection.Emit.OpCodes]::Ret)
    
    $typeBuilder.CreateType();
    $assemblyBuilder.SetEntryPoint($methodBuilder);
    $assemblyBuilder.Save("sample.exe")
}

Hello-World-Il

上記のコードを実行すると sample.exe が c:\temp 配下に作成されます。
この作成されたexeは、以下のコードをコンパイルして作成されるILとほぼ同じ振る舞いをするILとなります。

アセンブラとほぼ変わらんですね。なかなか大変な、、、

static void Main()
{
    Console.WriteLine("文字を入力して下さい。");
    var a = Console.ReadLine();
    Console.WriteLine(a + "と入力しました。");
    Console.ReadLine();
}