2012-10-17 79 views
5

我有這個序列的CIL代碼,我通過使用Mono.Cecil注入。但是,修改後的.NET C#應用程序將無法運行。NET CIL操作評估堆棧

目的:從棧 手動加載和彈出值在Console.WriteLine

for (int i = 0; i < 3; i++) 
     { 
      int z = some value popped manually from stack;     
      Console.WriteLine(z); 
     } 

這是我修改了簡單main()程序顯示:

.method private hidebysig static void Main(string[] args) cil managed 
{ 

    .entrypoint 
    .maxstack 5 
    .locals init (
     [0] int32 num, 
     [1] int32 num2) 
    L_0000: ldc.i4.6 //manually push value 6 to stack 
    L_0001: ldc.i4.5 //manually push value 5 to stack 
    L_0002: ldc.i4.4 //manually push value 4 to stack 
    L_0003: ldc.i4.0 //push int i initial value 0 to stack 
    L_0004: stloc.0 //pop and store to int i variable to variable num 
    L_0005: br.s L_0013 
    L_0007: nop 
    L_0008: stloc.1 //pop the pushed values 6,5 and 4 to variable num2 
    L_0009: ldloc.1 //load value of num2 to stack 
    L_000a: call void [mscorlib]System.Console::WriteLine(int32) //pop value of num2 and print 
    L_000f: ldloc.0 //load previous value in variable num to stack 
    L_0010: ldc.i4.1 //load incremental value 1 to stack 
    L_0011: add //pop and add the top 2 values, result is pushed to stack 
    L_0012: stloc.0 //store the new result to variable num. (int i) 
    L_0013: ldloc.0 //push int i variable value to stack 
    L_0014: ldc.i4.3 //push value 3 to stack as number of times to loop 
    L_0015: blt.s L_0007 //branch less than (pop and cmp the top 2 values in stack) 
    L_0017: ret 
} 

然而,上面的代碼不能運行。我嘗試將blt.s更改爲cltbr_true.s,但它也不起作用。有誰知道是否有可能實現我的目標?謝謝。

編輯: 根據ECMA-335,III.1.7.5,可能有一個後向分支約束。不知道這是否是這種情況。

特別地,如果該單個遍分析到達的指示時,稱之爲位置X,即 緊跟一個無條件分支,並且其中X是不是較早分支 指令的目標時,則狀態X的評估堆棧顯然不能從現有的 信息中派生出來。在這種情況下,CLI要求X處的評估堆棧爲空。

+3

你運行程序的實際錯誤是什麼?你有沒有試過對修改後的程序運行peverify? – Jeff

+2

您正在給驗證方*太多的困難時間來檢查堆棧是否平衡。它將不得不深入代碼來分析循環運行的頻率。它不這樣做。 –

回答

2

你IL代碼看起來不錯,但我認爲CLR可能無法檢查方法完成後堆棧是否損壞。當某些東西被壓入堆棧時,CLR檢查是否該值也從堆棧彈出。

所以如果你將3個值推入堆棧,CLR不能檢查你的循環是否運行了三次,所以當方法返回時CLR不知道是否仍有值進入堆棧。

+0

我懷疑這樣做,因爲堆棧在一個程序中是不穩定的,必須在「調用」之前清空。過於習慣二進制彙編提供的靈活性。 – Ron