深入理解計算機系統(3.5)------特殊的算術操作指令

分類:IT技術 時間:2017-10-02

  在上一篇博客 算術和邏輯操作 我們介紹了如下圖幾種常用的算術邏輯指令,但是大家發現沒,這幾種指令如果在 IA32 上只能操作32位寄存器,比如我用乘法指令IMUL得出的結果超過了32位,那就會產生結果溢出,那應該怎麽辦呢?

  

 

1、特殊的算術操作指令指令

  

  如上圖,上面的幾個指令支持有符號和無符號的全64位乘積以及整數除法,但是需要註意的是,存儲結果的寄存器固定死了,是一對寄存器%edx(高32位)和%eax(低32位)組成的 64 位的四字。

 

2、imull 和 mull 指令

  對於 imull 指令,上一章我們在講算術和邏輯操作指令的時候,講過這個指令,這是一個乘法指令,指令形式是 imull S D,這裏有兩個操作數,它將計算S和D的乘積並截斷為雙字,然後存儲在D當中。由於在截斷時,無符號以及有符號的二進制序列是一樣的,因此此處的乘法指令並不區分有符號和無符號。

  但是對於本章的 imull 指令,它和前面的所表示的乘法指令有所不同,這裏只有一個操作數,如上圖,它的指令形式是 imull S。但是實際上它還有一個默認的操作數——寄存器%eax,這兩者相乘,最終的結果是將高32位存入%edx 寄存器,低 32 位存入%eax 寄存器。

  如果我們只取低 32 位的結果,那麽這裏指令的意思和上篇博客所講的乘法指令意思是一樣的了,imull S D,只不過這裏的D是寄存器 %eax。

  這裏我們可以看一個實例:imull $0x3,我們假設此時%eax寄存器的值為0x82345600。也就是我們需要計算0x3*0x82345600的值,這裏直接給出兩者相乘的16進制表示,為0xFFFF FFFE 869D 0200。這個結果為64位的,因此我們寄存器的前後狀態如下所示。

  本實例引用:http://www.cnblogs.com/zuoxiaolong/p/computer17.html

  

  可以看到,%eax保存著低32位的結果,單說這32位的話,它的有符號數值為-2036530688,正是我們直接計算0x3*0x82345600的32位截斷後的有符號值,顯然這個結果溢出了。如果組合上高32位,則結果為-6331497984,將它加上或者取模4294967296(2的32次方)將得到我們32位的結果。這裏的有符號乘法采取的是先符號擴展被乘數,然後兩者相乘,將結果再截斷為64位所得。

  對於mull的單操作數指令來講,就比較簡單了,它采用的是無符號乘法,因此就和我們平時的十進制乘法運算類似,只是同樣的,它也會將結果的高32位存入%edx,將低32位存入%eax。

  所以雖然 imull 可以用於兩種不同的乘法操作,但是匯編器能夠通過計算操作數的數據,分辨出想用哪條指令。

3、cltd 指令

  這個指令就是簡單的將%eax寄存器的值符號擴展32位到%edx寄存器,也就是說,如果%eax寄存器的二進制序列的最高位為0,則cltd指令將把%edx置為32個0,相反,如果%eax寄存器的二進制序列最高位為1,則cltd指令將會自從填充%edx寄存器為32個1。

 

4、idivl、divl指令

  這兩個指令分別是有符號除法和無符號除法指令,有符號除法指令 idivl 將寄存器 %edx(高32位)和 %eax(低32位)中的64位數作為被除數,而除數作為指令的操作數給出。指令將商存儲在寄存器 %eax 中,將余數存儲在寄存器 %edx 中。

  比如指令idivl $0x3的結果,我們假設此時%eax寄存器的值為0x82345600。也就是我們需要計算0x82345600/0x3的值,這裏直接給出兩者相除的16進制表示,商為0xD6117200,余數為0x0。因此我們寄存器的前後狀態如下所示。

  

  可以看到,在idivl這個指令執行的過程中,其實對被除數進行了符號擴展,類似於cltd指令,或者有時也會將%eax移動到%edx,然後對%edx進行算術右移31位的運算。這兩種方式的結果是一樣的,都是將%eax符號擴展32位並存儲在%edx當中。


Tags: 指令 寄存器 乘法 算術 符號 操作數

文章來源:


ads
ads

相關文章
ads

相關文章

ad