今天在處理 x86 匯編專案時,我嘗試%rax通過%rbx使用salq-operation的值左移暫存器的值,但無法使其作業。當然,使用立即值移位效果很好,但是我不知道為什么我不能使用暫存器。我什至嘗試使用%bl,考慮到我在編譯時收到的錯誤是運算元大小錯誤,我認為這是問題所在的大小 - 仍然沒有作業。
經過大量試驗和錯誤后,一位朋友將我鏈接到一個頁面,說明這%cl是唯一可用于sal. 瞧——現在我的代碼可以作業了。我的好奇心是,就技術方面而言,為什么%cl是我們唯一可以使用的,而其他三個暫存暫存器中沒有一個應該相同?在網上找不到任何關于此的資訊,所以希望這里有人在 x86-Assembly 上投入了足夠的資金來解釋這一點。:)
uj5u.com熱心網友回復:
這個限制來自 8086,所以我們必須一路回到那里來嘗試猜測基本原理。
一種可能的提示來自編碼。您可能知道,大多數 8086 ALU 指令由一個一位元組的操作碼和一個指定運算元的 Mod-Reg-R/M 位元組、一個暫存器和一個可以是暫存器或記憶體的 R/M 組成。暫存器運算元在該位元組的 3 位 Reg 欄位中指定,R/M 運算元由其余 5 位指定。
在移位的情況下,我們實際上有 7 條不同的指令共享一個操作碼。操作碼 D2 用于所有 8 位變數移位和旋轉指令:
rol r/m8, cl
ror r/m8, cl
rcl r/m8, cl
rcr r/m8, cl
shl r/m8, cl
shr r/m8, cl
sar r/m8, cl
由于cl移位計數的運算元是硬編碼的,因此暫存器運算元不需要 Mod-Reg-R/M 位元組的 Reg 欄位,而是可以用來區分這些指令。這在指令串列中進行了標記,例如
D2 /2 rcl r/m8, cl
換句話說,rcl r/m8, cl使用操作碼 D2 和 3 位 Reg 欄位中的值 2。
(shl r/m8, cl實際上有兩種編碼,D2 /4 和 D2 /6。可能第 1 位用于表示邏輯或算術移位,因為shr和sar分別是 D2 /5 和 D2 /7。所以在某種意義上 D2 /4 可能是shl和 D2 / 6 是sal,但實際上是相同的操作。)
16 位變數移位和旋轉是相同的,但使用操作碼 D3。
因此,通過對移位計數暫存器進行硬編碼,指令集設計者必須在僅使用一個可用操作碼的情況下對 7 條指令進行編碼。如果他們允許使用任意暫存器,他們將需要 7 個不同的操作碼用于 8 位移位和旋轉指令,而 16 位版本則需要 7 個不同的操作碼。該操作碼地圖是相當擁擠。我想當時有 60-6F可用,但他們可能想保留它們以備后用。否則,他們將不得不放棄其他地方的指令,或者采用更復雜的編碼方案,這意味著在解碼器上花費更多的晶體管。
仍然存在他們為什么cl特別選擇而不是說的問題bl。他們確實有使用的一般哲學cx作為“計數”的暫存器,另一個指令硬編碼cx傾向于使用它作為某種計數:loop和rep為實體。他們可能認為這會讓程式員更容易記住。
正如 fuz 所指出的,后來的BMI2擴展確實添加了shlx/shrx/sarx,它可以從任意暫存器中獲取移位計數,但它們必須被硬塞到指令空間的一個奇怪的角落中,并且具有更復雜的編碼 - 需要一個 VEX 前綴總共 5 個位元組或更多要編碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/328588.html
上一篇:IDA專業人士了解反匯編細節
下一篇:為什么這個匯編程式不接受輸入?
