[英]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字節
0x84
是ModRM字節 ,在這種情況下編碼使用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.