[英]Is an empty evaluation stack required before an exception block?
當我刪除Ldstr "a"
並Call Console.WriteLine
(在Ret
之前)時,代碼運行正常,否則在調用時拋出InvalidProgramException
。 這是否意味着需要一個空的評估堆棧?
class Program
{
delegate void Del();
static void Main(string[] args)
{
DynamicMethod dynamicMethod = new DynamicMethod("", null, Type.EmptyTypes);
ILGenerator ilGen = dynamicMethod.GetILGenerator();
ilGen.Emit(OpCodes.Ldstr, "a");
ilGen.BeginExceptionBlock();
ilGen.Emit(OpCodes.Ldstr, "b");
ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null));
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();
ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null));
ilGen.Emit(OpCodes.Ret);
((Del)dynamicMethod.CreateDelegate(typeof(Del))).Invoke();
}
}
為了理解你在做什么,我建議你盡可能做一個最小的例子。
ilGen.Emit(OpCodes.Ldstr, "a");
ilGen.BeginExceptionBlock();
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();
ilGen.Emit(OpCodes.Pop);
ilGen.Emit(OpCodes.Ret);
之后,您可以使用AssemblyBuilder
將給定代碼轉儲到可執行文件中。 如果完成, ildasm
將顯示已生成的內容。
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldstr "a"
.try
{
IL_0005: leave IL_000f
} // end .try
catch [mscorlib]System.Exception
{
IL_000a: leave IL_000f
} // end handler
IL_000f: pop
IL_0010: ret
正如您所看到的,我們將達到跳轉到pop
的leave
指令。 然后你可以谷歌關於leave
,其中說明:
leave指令類似於br指令,但它可用於退出try,filter或catch塊,而普通分支指令只能在這樣的塊中用於在其中傳輸控制。 leave指令清空評估堆棧並確保執行適當的周圍finally塊。
但是,為什么以下的工作沒有呢?
ilGen.Emit(OpCodes.Ldstr, "a");
ilGen.BeginExceptionBlock();
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();
//ilGen.Emit(OpCodes.Pop);
ilGen.Emit(OpCodes.Ret);
我懷疑它可能不是“物理限制”,而是驗證問題。 讓我們運行peverify ourapp.exe
,看看我們得到了什么:
[IL]: Error: [C:\temp\test.exe : Program::Main][offset 0x00000005] Attempt to en
ter a try block with nonempty stack.
1 Error(s) Verifying C:\temp\test.exe
在這一點上,你可能會像,掃管笏? 通過一點谷歌搜索,你可以得到一個錯誤代碼0x801318A9 。 通過SSCLI2.0快速掃描來源:
case ReaderBaseNS::RGN_TRY:
// Entering a try region, the evaluation stack is required to be empty.
if (!m_readerStack->empty()) {
BADCODE(MVER_E_TRY_N_EMPTY_STACK);
}
break;
現在,這很酷,但如果你很討厭,你可能想知道為什么評估堆棧必須是空的?
為此,您可能希望了解ECMA C#和公共語言基礎結構標准 。 我懷疑你可以從PartitionIII CIL.pdf中找到原因
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.