簡體   English   中英

AMD64 - nopw匯編指令?

[英]AMD64 — nopw assembly instruction?

在這個編譯器輸出中,我試圖理解nopw指令的機器碼編碼是如何工作的:

00000000004004d0 <main>:
  4004d0:       eb fe                   jmp    4004d0 <main>
  4004d2:       66 66 66 66 66 2e 0f    nopw   %cs:0x0(%rax,%rax,1)
  4004d9:       1f 84 00 00 00 00 00

http://john.freml.in/amd64-nopl上有一些關於“nopw”的討論。 任何人都可以解釋4004d2-4004e0的含義嗎? 從查看操作碼列表看, 66 ..代碼似乎是多字節擴展。 我覺得我可能會得到一個比這更好的答案,除非我試圖在幾個小時內查看操作碼列表。


asm輸出來自C中的以下(瘋狂)代碼,它優化為簡單的無限循環:

long i = 0;

main() {
    recurse();
}

recurse() {
    i++;
    recurse();
}

當使用gcc -O2編譯時,編譯器會識別無限遞歸並將其轉換為無限循環; 它實際上做得很好,事實上,它實際上在main()循環而不調用recurse()函數。


編者注:帶NOP的填充函數並不特定於無限循環。 Godbolt編譯器資源管理器中 ,這是一組具有一系列NOP長度的函數

0x66字節是“操作數大小覆蓋”前綴。 擁有多個這些相當於擁有一個。

0x2e在64位模式下是一個'空前綴'(否則它是CS:段覆蓋 - 這就是它出現在匯編助記符中的原因)。

0x0f 0x1f是NOP的2字節操作碼,采用ModRM字節

0x84ModRM字節 ,在這種情況下編碼使用5個字節的尋址模式。

一些CPU很難解碼具有許多前綴的指令(例如,多於三個),因此指定SIB + disp32的ModRM字節是比使用五個以上前綴字節多出5個字節的更好方法。

Agner Fog microarch的AMD K8解碼器pdf

每個指令解碼器可以在每個時鍾周期處理三個前綴。 這意味着可以在同一時鍾周期中解碼具有三個前綴的三個指令。 具有4 - 6個前綴的指令需要額外的時鍾周期來解碼。


本質上,這些字節是一條長NOP指令,無論如何都不會被執行。 它在那里確保下一個函數在16字節邊界上對齊,因為編譯器發出了一個.p2align 4指令,因此匯編.p2align 4 NOP填充。 gcc的x86默認值是
-falign-functions=16 對於將要執行的NOP,長NOP的最佳選擇取決於微體系結構。 對於在許多前綴上窒息的微體系結構,如Intel Silvermont或AMD K8,兩個帶有3個前綴的NOP可能解碼得更快。

鏈接到( http://john.freml.in/amd64-nopl )的問題的博客文章解釋了為什么編譯器使用復雜的單個NOP指令而不是一堆單字節0x90 NOP指令。

您可以在AMD的技術參考文檔中找到有關指令編碼的詳細信息:

主要在“AMD64架構程序員手冊第3卷:通用和系統指令”中。 我確信英特爾對x64架構的技術參考將具有相同的信息(甚至可能更容易理解)。

匯編程序(不是編譯器)使用可以找到的最長NOP指令將代碼填充到下一個對齊邊界。 這就是你所看到的。

我猜這只是分支延遲指令。

我相信nopw是垃圾 - 我從未在你的程序中讀過,因此沒有必要增加它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM