2008-10-24 126 views
69

我正在通過MSIL,並注意到有很多nop說明。 MSDN文章說,他們不採取任何行動,如果操作碼被修補,則用於填充空間。它們在調試構建中比發佈構建中用得更多。我知道在彙編語言中使用這些類型的語句來確保操作碼符合字邊界,但爲什麼它在MSIL中需要?nop操作碼的用途是什麼?

+18

這些答案在語言編譯程序發出的MSIL nop指令與程序集運行時JIT編譯器發出的x86 nop指令(在該平臺上)之間存在質量混淆。 [事實上,接受的答案是關於x86的nops,並且與MSIL沒有任何關係。] 理想情況下,這個問題應該分成兩個不同的問題:MSIL :: nop的目的是什麼?和本地平臺nop的目的? – 2009-11-29 19:57:38

回答

88

的NOP一舉數得:

  • 他們允許調試器放置一個斷點,即使與他人在生成的代碼相結合的線。
  • 它允許加載程序用不同大小的目標偏移量來跳轉跳轉。
  • 它允許一段代碼在特定的邊界對齊,這對緩存很有好處。
  • 它允許增量鏈接以調用新的部分來覆蓋代碼塊,而不必擔心整體功能會改變大小。
8

它爲代碼中的基於行的標記(例如斷點)提供了一個機會,在該代碼中,發佈版本不會發出任何消息。

+0

斷點是否需要一個nop?爲什麼不在普通操作碼上放一個斷點? – 2008-10-24 19:23:43

+4

許多常規操作碼在發佈版本中得到了優化。這會弄亂你的斷點,除非有一個佔位符,否則斷點仍然指向 – Jimmy 2008-10-24 19:28:49

+1

在調試版本中,它們也被用來提供一個指令來打破代碼沒有指令的地方。例如,打開大括號。 – 2008-10-24 19:31:29

3

它們的一個經典用法是讓調試器始終可以將源代碼行與IL指令相關聯。

+0

難道這不可能發生嗎? – 2008-10-24 19:24:17

+0

由於msil在運行時編譯爲JIT,因此可能會丟失該映射(例如,本機指令沒有唯一的MSIL指令)。 NOP被用作從語言編譯器到JIT編譯器的通信機制來保存這種映射。 – 2008-12-28 18:18:50

4

老兄! No-op太棒了!這是一種無用之事,但消耗時間的指令。在昏暗的黑暗時代,您可以用它在關鍵循環中進行微調,或者更重要的是作爲自我修改代碼中的填充。

1

它們允許鏈接器用較短的指令(短跳轉)替換較長的指令(通常是跳轉)。 NOP需要額外的空間 - 代碼不能移動,因爲它會阻止其他跳轉工作。這發生在鏈接時間,所以編譯器無法知道長短跳是否合適。

至少,這是他們的傳統用途之一。

3

他們可能會在調試時使用它們來支持編輯和繼續。它爲調試器提供了工作空間,可以在不更改偏移量的情況下替換舊代碼。

1

這不是您的具體問題的答案,但回到過去,您可以使用NOP填充branch delay slot ,如果你不能用其他有用的指令填寫它。

1

.NET編譯器對齊MSIL輸出嗎?我想這對於加速訪問IL可能是有用的......另外,我的理解是,它的設計是可移植的,並且在一些其他硬件平臺上需要對齊訪問。

2

在軟件破解的場景中,解鎖應用程序的一個經典方法是使用NOP補丁來檢查密鑰或註冊或時間段,或者不會做任何事情的行,並簡單地繼續啓動應用程序如果它被註冊。

2

我也看到了代碼中的NOP,它修改自身以混淆它作爲佔位符(veeery舊版本保護)的功能。

1

的第一組裝我的教訓是SPARC所以我很熟悉的分支延遲槽,如果你不能與其他指令填充它,通常是指示你打算把分支指令高於或遞增計數器循環,你使用NOP。

我不熟悉的開裂,但我認爲這是常見的覆蓋使用NOP所以你沒有精確地計算你的惡意功能開始在堆棧。

4

它也可能使代碼運行速度更快,在爲特定處理器或體系結構優化時:

處理器很長一段時間採用的是並行粗略工作的多個管道,讓兩個獨立的指令能夠在同一時間exceuted。在具有兩個管道的簡單處理器上,第一個可以支持所有指令,而第二個僅支持一個子集。另外,當需要等待前一條尚未完成的指令的結果時,管道之間會有一些停頓。

在這種情況下,專用NOP可能迫使下一個指令到特定的管道(第一,或不是第一次),並提高了以下說明配對,以便NOP的費用比較比攤銷。

3

Nop在緩衝區溢出攻擊的有效負載中非常重要。

3

正如ddaa所說,nops讓你在堆棧中考慮了方差,這樣當你覆蓋返回地址時,它會跳轉到nop sled(連續很多nops),然後正確地命中可執行代碼,而不是跳轉到不是開始的指令中的某個字節。

9

下面是空指令是如何被用於調試:

瑞爾是由語言編譯器使用(C#,VB等)來定義隱序列點。這些告訴JIT編譯器在哪裏確保機器指令可以映射回IL指令。

DebuggingModes.IgnoreSymbolStoreSequencePoints裏克·拜爾的博客文章,解釋了一些細節。

C#還會在呼叫指令後放置Nops,以便源中的返回站點位置是呼出而不是呼叫後的線路。

1

我使用NOP來自動調整進入ISR後累積的延遲。非常方便指定時間死亡。

2

一種略爲非正統的用途是NOP-Slides,在緩衝區溢出攻擊使用。

3

50年太晚了,但嘿。

如果您手動輸入彙編代碼,則Nop's非常有用。 如果您必須刪除代碼,則可以禁用舊操作碼。

similary,你可以通過覆蓋一些操作碼並在其他地方跳轉來插入新的代碼。在那裏你把覆蓋的操作碼,並插入你的新代碼。準備好後,你跳回來。有時你不得不使用可用的工具。在某些情況下,這只是一個非常基本的機器碼編輯器。

現在使用編譯器,這些技術再也沒有意義了。

2

在我最近工作的一個處理器(四年)中,NOP被用來確保在下一個操作開始之前先前的操作完成。例如:

負載值寄存器(需要8個週期) NOP 8 加1寄存器

這確信寄存器有該加載操作之前的正確的值。

另一個用途是填充執行單元,例如中斷向量必須是一定的大小(32字節),因爲vector0的地址是0,對於向量1 0x20等等,所以編譯器把NOP在那裏如果需要的話。