彙編語言符號擴展指令及應用示例

1. 什麼是符號擴展?爲什麼要用符號擴展?

       所謂符號擴展,就是將數據的表示大小加倍,數值仍保持不變,即將符號位擴展到同樣大小的寄存器空間中去,由兩部分構成一個比原值表示大一倍的數。正數必須要0擴展,負數必須用1擴展。

爲什麼要進行符號擴展呢?有些指令對操作數位數的要求,例如倍長於除數的被除數,再如將數據位數加長以減少計算過程中的誤差。另外,除法運算中規定

除數是BYTE,被除數AX,商存放在AL,餘數放在AH

除數是WORD,被除數DX:AX,商存放在AX,餘數放在DX

除數是DWORD,被除數EDX:EAX,商存放在EAX,餘數放在EDX

被除數總是除數和商的兩倍大小,由於餘數的符號取決於被除數的符號,計算之後的餘數存放在AH,DX,或者EDX中,那麼執行除法之前,先將被除數的符號擴展到餘數存放寄存器中,這也要求符號擴展。

        事實上,在彙編語言裏面,有符號數與無符號數計算,很多地方都分成了兩套指令,進位與符號操作,都交由程序員來判斷和操作,符號擴展正是這一設計思想的體現。

2. 符號擴展指令及應用示例

2.1  CBW(Convert Byte to Word):

規定將AL中的符號擴展到AX中,這是規定死的,執行這個指令就將AL中的符號擴展到AX中了。通過符號擴展,將AL的操作數大小擴大1倍,字節表示的數用字表示,將結果存入AX中。AL中的符號位第7位,複製到AH中的每一位。例如

XOR EAX,EAX

MOV AL,-128

此時EAX=0x80二進制10000000

CBW

此時EAX=0xFF80進制11111111 10000000符號位1,高8位用符號位1全部填充。

2.2  CWD(Convert Word to Doubleword):

規定將AX中的符號擴展到DX中,執行這個指令就將AX中的符號擴展到DX中了,那爲什麼不直接將AX中的符號擴展到EAX中,而要那麼麻煩的擴展到DX中,再用DX:AX來表示一個有符號數呢,例如,後面的CWDE就是這麼幹的?估計是在符號擴展指令出來時,還沒有32位機,如8086就是16cpu,也就沒有EAX寄存器,只能用兩個16位寄存器來表示32位數了,後續32位爲了兼容16位時寫的程序,也就保留了這種操作方法。另外用於在有符號除法運算中,AX存放商,DX存放餘數,不將符號擴展到DX中,IDIV指令是不會將負號自動填進去的,會使用計算結果不正確。

通過符號擴展,將AX中的操作數大小擴大1倍,字表示的數用雙字表示,將結果存入DX:AX中,用兩個字寄存器存儲1個雙字的數。例如

XOR EAX,EAX

XOR EDX,EDX

MOV AX,-32768

此時AX=0x8000二進制10000000 00000000

CWD

此時AX=0x8000進制10000000 00000000符號位1,而DX=0xFFFF,即符號位1被填充到了DX。

2.3  CDQ(Convert Doubleword to Quadword):

規定將EAX中的符號擴展到EDX中,執行這個指令就將EAX中的符號擴展到EDX中了。同樣,當兩個32位有符號數相乘時,符號位就超出了32位表示的範圍,像前一樣,用兩個寄存器EDX:EAX來表示這個乘法的結果,從而得到正確的計算結果。同理,64位出現後,爲了兼容32位的程序,也保留了這種操作。同樣,在有符號除法運算中,EAX存放商,EDX存放餘數,不將符號擴展到EDX中,IDIV指令是不會將負號自動填進去的,會使用計算結果不正確。通過符號擴展,將EAX中的操作數大小擴大1倍,雙字表示的數用四字表示,將結果存入EDX:EAX中,用兩個雙字寄存器存儲1個四字的數。例如

XOR EAX,EAX

XOR EDX,EDX

MOV EAX, -2147483648

此時EAX=0x8000 0000二進制10000000 00000000 00000000 00000000

CWD

此時EAX=0x80000000進制10000000 00000000 00000000 000000000符號位1,而EDX=0xFFFFFFFF,即符號位1被填充到了EDX。

2.4  CQO(Convert Quadword to )

     規定將RAX中的符號擴展到RDX中去,這是64cpu模式下使用的指令。用以表示128位的數據,因爲兩個64位數操乘法運算超過64位的範圍,採用以上的表示方法。同樣,在有符號除法運算中,RAX存放商,RDX存放餘數,不將符號擴展到RDX中,IDIV指令是不會將負號自動填進去的,會使用計算結果不正確。通過符號擴展,將RAX中的操作數大小擴大1倍,四字表示的數用八字表示,將結果存入RDX:RAX中,用兩個四字寄存器存儲1個八字的數。例如

XOR RAX,RAX

XOR RDX,RDX

MOV RAX, -9223372036854775808

此時RAX=0x8000000000000000二進制

1000000000000000000000000000000000000000000000000000000000000000

CQO

此時RAX=0x8000000000000000 符號位1,而RDX=0xFFFFFFFFFFFFFFFF,即符號位1被填充到了RDX。

 

2.5  CWDE(Convert Word to Doubleword):

這個E(Extension)應該是指相對於CWD的擴展,是稍後面加的指令,CWD指令出現的時間比CWD早。規定將AX中的符號擴展到EAX中,執行這個指令就將AX中的符號擴展到EAX中了。

CWDE同CWD,只是符號位是直擴展到EAX的高16位中了。

2.6  CDQE(Convert Doubleword to Quadword):

    這個E(Extension)應該是指相對於CWQ的擴展,同樣,CWD指令出現的時間比CDQE早。

規定將EAX中的符號擴展到RAX中,執行這個指令就將EAX中的符號擴展到RAX中了。

    CDQE同CDQ,符號被擴展到RAX的高32位中了。

2.7 MOVZX指令將源操作數的內容複製到目的操作數中,並將該值零擴展至16位或32位。該指令僅適用於無符號整數。

爲什麼要有這個指令呢,因爲MOV指令不能將一個較小的操作數複製到一個較大的操作數。

類爲MOV指令要求兩個操作數必須一樣大。比如將一個較小的操作數在寄存上執行MOV操作,則寄存器的高位沒有被覆蓋,這個時候我們取整個寄存器值作爲MOV的結果是不對的,例如

data1 BYTE 1

data2 WORD ?

XOR EAX,EAX

MOV AX,0FFFFH

MOV AL,data1

MOV data2,AX

這個時候,data2變成了FF01,而不是1。要得到正確的結果,可以有多種方法

比如,先將高位清零

XOR EAX,EAX

MOV AL,data1

MOV data2,AX

這樣data2=1

或者就直接使用這個指令

MOV AX,0FFFFH

MOVZX AX,data1

MOV data2,AX

2.8 MOVSX指令將源操作數的內容複製到目的操作數中,並將該值符號擴展至16位或32位。該指令僅適用於有符號整數。例如

data1 SBYTE -1

data2 SWORD ?

XOR RAX,RAX

MOV AL,data1

MOV data2,AX

這個時候,data2的值爲255了,而不是-1,也就是MOV並沒有把FF當成有符號數,而是當作值了,那麼用MOVSZ就不一樣了。

XOR RAX,RAX

MOVSX AX,data1

MOV data2,AX

這個時候data2=-1,是正確的結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章