回來開電腦, 別人都黑店去了。我沒趕上。
剩下我無聊的琢磨著研究點什麼呢?
最近要寫一個監聽事件的東西, 反射出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。。