硬著頭皮看IL之一 :和IL的第一次約會

來源:互聯網
上載者:User

回來開電腦, 別人都黑店去了。我沒趕上。
剩下我無聊的琢磨著研究點什麼呢?

最近要寫一個監聽事件的東西, 反射出EventInfo之後要動態構造方法,
傳參數要傳一個OpCodes。 一查協助, 居然是代表IL的一個東東。

無比鬱悶。 於是看下能不能看懂。

從最簡單的開始吧。 因為微軟給的教IL的教程實在是太痛苦了。

我把C#代碼編譯成dll, 然後用reflector反編譯回來看看能不能看懂好了。

C#代碼:
public void TestMethod()
{
    int a = 3;
    int b = 4;
    int c = a + b;
}
很簡單吧! 但是切出來就很鬱悶了。

切換到IL:
.method public hidebysig instance void TestMethod() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 a,
        [1] int32 b,
        [2] int32 c)
    L_0000: nop
    L_0001: ldc.i4.3
    L_0002: stloc.0
    L_0003: ldc.i4.4
    L_0004: stloc.1
    L_0005: ldloc.0
    L_0006: ldloc.1
    L_0007: add
    L_0008: stloc.2
    L_0009: ret
}
對照著OpCodes類, 似乎也能看懂一點。
前面亂七八糟的定義暫且跳過。 似乎超出我能力範圍了。
第一句就是nop。
無效指令。 湊位元的。 大概這個意思吧?可能是湊夠多少位能提高執行速度?
純猜測。
第二句就是ldc.i4.3
我注意到ldc.i4的意思是, 把一個數字推入計算用的棧。
而ldc.i4.3則是一個整體指令, 意思是把3壓入棧中。 我查閱OpCodes定義的時候注意到有9個指令(0到8)

是用於把一個指定的值壓入棧, 其他的資料要使用ldc.i4加一個數值來實現。 應該是因為這幾個數字比

較常用吧?而且8恰好是2的三次方。
這個計算用的棧很有趣。 似乎大部分操作都是在折騰這個東東, 讓我不禁想起了學C的時候的指標。

跑啊跑的, 不小心就把結果給算出來了。
ld應該就是load的縮寫吧? 猜測。 但是那個c。。。 無限遐想。。。

第二句是stloc.0,
set local, 這個意思吧? 把棧頂的資料放到局部變數列表的0號裡面去。 也就是那個 a。 這句話就是:

把棧頂彈出來, 賦給a。 這樣a就得3了。 然後棧又空了。
 
然後兩句是ld.i4.4, stloc.1
意思就是把4壓入棧, 然後再彈出去給b

感覺好睏惑啊, 彈來彈去的。
現在棧又空了, 對吧?
後面就有趣了:
ldloc.0, ldloc.1
猜測應該是load local 的縮寫吧。
把0號局部變數(a)壓入棧, 再把1號局部變數(b)壓入棧。

也就是費了半天是彈出去還要在load回來。。 orz
似乎目的只是為了保證棧內的資料是對的。而且沒有不彈出直接讀的辦法吧。 我估計。
要不微軟幹嘛如此麻煩的折騰來折騰去? 是另有隱情, 還是高深莫測?或者乾脆就是逗我玩?

額, 壓棧的目的就是下一句:
add,把棧頂的兩個數字相加,
MSDN詳細解釋是:
----------------------
value1 被推送到堆棧上。

value2 被推送到堆棧上。

value2 和 value1 從堆棧中彈出;value1 被添加到 value2 中。(Arthas註:這句話很歧義啊。。)

結果被推送到堆棧上。
-------------------------

前兩步應該是程式員自己做的, 也就是那兩個load。後兩步是add指令做的。
現在棧頂的數值是加的結果了。 我們要賦給c
所以:
stloc.2
把棧頂的資料給2號變數也就是c, 棧又空了。void函數就這樣走完了。

然後ret, 明顯是return了。

這是一個void類型的函數。 如果傳回值是int呢? 例如把c返回去?
把最後一句改成:
return a + b;

reflector告訴我, 是這樣的:
    .maxstack 2
    .locals init (
        [0] int32 a,
        [1] int32 b,
        [2] int32 CS$1$0000)
    L_0000: nop
    L_0001: ldc.i4.3
    L_0002: stloc.0
    L_0003: ldc.i4.4
    L_0004: stloc.1
    L_0005: ldloc.0
    L_0006: ldloc.1
    L_0007: add
    L_0008: stloc.2
    L_0009: br.s L_000b
    L_000b: ldloc.2
    L_000c: ret
這個br.s L_000b, 很困惑啊, 什麼意思呢?
br.s , 是強制跳轉。 強制跳轉到下一句, 有什麼意義嗎? 不理解。似乎有什麼高深的理論在裡面? 尋求解答。。。

結尾是ldloc.2, 也就是把那個CS$1$0000壓到棧頂就可以返回了。 也就是說傳回值是扔到棧頂的。。 這

個似乎和學C的時候有些不同額。。。

這個棧實在太IMBA了。

總結: reflector太強大了。

能看懂這段暈頭轉向的東西完全歸功於reflector的一個很炫的功能:
mouse hover到指令上, 就提示你這句指令是什麼意思。。。

太IMBA了。。。

下次計劃。。 調函數。。 看參數是如何轉化的。。
如何壓來彈去的。。

調皮的IL。。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.