2017-06-16 175 views
-1

我試圖反彙編我的C#代碼,然後在彙編語言級別進行調試。 比方說,我們有一個簡單的C#方法:如何正確反彙編.NET代碼?

var a = 1235; 
var b = ++a; 
var c = ++b; 

Console.WriteLine("test"); 
Console.ReadKey(); 

我發現了兩種不同的方式如何獲取彙編代碼。 第一個是在VS中啓動C#代碼調試,然後打開Disassembly窗口。這裏我們有以下代碼。

first method assembly

一切行和彙編代碼是非常簡單和短,但問題是,這個彙編代碼邏輯由ILDASM產生的IL代碼的邏輯是不同的。

cil code

因此,這裏是第二種方式。我們可以編譯C#代碼,使用ILDASM獲得從PE文件中的IL代碼,然後用ILASM生成PE文件恢復。現在我們有以下彙編代碼。

second method code

正如你可以看到這個彙編代碼更像是IL代碼,但它包含更多的指令,這是更爲複雜。

AFAIK C#編譯爲CIL代碼,然後在這兩種情況下的彙編代碼。但它似乎是以第一種方式編譯爲彙編代碼。

所以,問題是爲什麼第一方法的彙編代碼從IL代碼不同?爲什麼第一種方法的彙編代碼與第二種方法的彙編代碼不同?

+3

CLR是一個虛擬機,因此代碼的區別。類似於Java的JVM。 – t0mm13b

+4

這是調試模式的代碼(你可能有「禁止對模塊加載JIT優化」打開),這樣不是很有趣,但奇怪的是,這取決於它是否已經通過反彙編/ ILASM往返走了是不同的。 – harold

+6

這不是一個「問題」,它是一個功能。在使用Release版本並關閉Suppress JIT優化選項時,僅查看機器代碼是明智的。 –

回答

2

的JIT能夠重新排序和合並的機器指令作爲optomisation,但會盡量避免移動由PDB提供跨sequence points的影響。編譯器通常會爲每行代碼生成一個序列點,因爲您通常一次一行地遍歷它。

雖然C#往往會產生每行代碼多個IL指令,ILASM被明確給定每個指令並這樣生成更多的序列點,留下用於JIT優化的空間更小。

+0

這個答案不是很準確,PDB文件肯定與序列點無關。 「代碼行」也不是。代碼提升和子表達式消除是JIT優化器知道也適用的標準優化器技術。 Backgrounder post [在這裏](https://stackoverflow.com/a/4045073/17034)。 –

+1

@HansPassant,我想你可能會把PDB的序列點概念和C++概念混淆在同一個名字中。 pdb使用術語「序列點」來描述[IL <->源映射](https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedmethod-getsequencepoints-method)。這個想法是,一個調試器很可能會停止在一個「序列點」的開始處,所以JIT會嘗試使這些事情看起來一致(除非通過我鏈接到的文章中描述的DebuggableAttribute標誌來告知其他事項在答案中。) –

+0

感謝您的教訓,從未見過這個術語的用法。未來的讀者可能想知道,優化器不會嘗試保持PDB信息的相關性。使用默認的項目配置,PDB甚至不包含任何行號信息。 –