整數運算

這一節介紹如何在編語言中上使用整數運算,包括加法、減法、乘法和除法。

  • 加法指令 add指令用於把兩個整數想加。格式如下:
add src, dest

其中src可以是立即數值、內存地址、寄存器。dest可以是寄存器或內存中的值,不能同時使用內存地址作為源和目標。結果存放在dest中。和其他GNU彙編指令一樣,需要在add結尾添加b、w、l來指定操作數長度。如果沒有使用整個寄存器,就要確保零填充目標寄存器,使得寄存器高位沒有內容。add指令可以對所有帶符號的整數執行加法操作。

在執行整數想加時,應該注意EFLAGS寄存器,當在無符號數做加法操作造成進位(結果大於允許的最大值)情況時,進位標誌會被置為1。在有符號整數出現溢出情況時(結果小於允許最小負值或大於允許最大正值),溢出標誌會被設置為1。下面示例演示無符號整數加法進位的情況:

#add1.s
.section .text
.globl _start
_start:
    nop
    movl $0, %ebx
    movb $240, %bl
     movb $20, %al
#    movb $2, %al
    addb %al, %bl
    jc over
    movl $1, %eax
    int $0x80

over:
    movl $1, %eax
    movl $0, %ebx
    int $0x80

如果加法操作造成進位,則把進位標誌設置為1,程序返回0,否則返回加法的結果。我們分別修改上述代碼使其造成進位和不進位(取消代碼註釋行且註釋上一行代碼),分別make、執行結果如下:

$ make
as -o add1.o add1.s --gstabs
ld -o add add1.o
$ ./add
$ echo $?
0
$ vim add1.s//修改代碼,使其不進位
$ make clean;make
rm -f add1.o add *~
as -o add1.o add1.s --gstabs
ld -o add add1.o
$ ./add
$ echo $?
242    //不進位時程序返回加法結果

在執行無符號整數加法時,總應該檢查進位標誌,如果知道輸入值界限,就可以不必檢查進位標誌。 在處理有符號整數,不需要判斷進位標誌,而是需要注意溢出標誌,當結果溢出正值或負值界限時,這個標誌會被設置為1。 使用adc指令可以處理大於雙字數據長度的加法。

  • 減法指令

減法操作和加法操作類似,減法指令是sub,格式類似加法指令:

sub src, dest

減法指令也需要在sub末尾添加b、w、l。和add指令類似,sub指令也會修改EFLAGS寄存器的位。 使用進位標誌確定無符號整數減法產生負數結果的情況。有符號數的減法需要依靠溢出標誌來判斷數據長度界限的情況。

sbb指令類似adc指令,可以使用進位情況幫助執行大的無符號整數的減法操作。

  • 遞增遞減指令

    • inc指令和dec指令可分別對無符號整數值進行遞增和遞減操作。這兩個指令不會影響進位標誌。指令格式如下:
      • dec dest
      • inc dest
      • dest可以是8位、16位、32位寄存器和內存中的值。
  • 乘法指令 mul指令用於兩個無符號整數相乘,格式如下:

mul src

src可以是8、16、32位寄存器或內存值。使用GNU彙編器時,命令助記符結尾加上正確長度字符。

該指令的目標操作數是隱含的。根據元操作數的值長度,乘法操作使用另一個操作數必須放在al、ax、eax寄存器中。由於乘法可能產生很大的值,所以mul指令目標位置必須是元操作數的兩倍長度。下表是無符號整數乘法的需求:

源操作數長度(位)
目標操作數
目標位置
8
AL
AX
16
AX
DX:AX
32
EAX
EDX:EAX

imul命令可以進行有符號整數的乘法。 imul指令有三種指令格式:

imul src    #這種指令格式和mul的使用一樣
imul src,dest    #允許指定eax之外的目標操作數
imul multipler, src, dest    #multipler是立即值
  • 除法指令
無符號除法指令:div divisor
有符號除法指令:idiv divisor

divisor是隱含被除數要除以的值。

  • 移位指令

在平時編寫高級語言時,都知道乘法和除法是很消耗處理器時間的,有些時候會使用移位來代替乘除法。在彙編語言中一樣,也可以使用移位,移位指令提供基於2的乘方的乘法和除法。把二進制數字左移1就是乘以2,左移2位就是乘以4,移位操作比執行二進制乘法操作要快得多。

  • 向左移位命令:sal(算數左移)和shl(邏輯左移),這兩個指令執行相同操作。有3種格式:
sal dest    #左移一位,等同於乘以2
sal %cl, dest    #左移cl寄存器中的數
sal shifter, dest    #左移shifter值指定的數

左移指令可以對無符號和有符號整數執行向左移位指令,空位補0,超出數據長度的位首先存放在進位標誌中,在下一次移位操作中被丟棄。

  • 向右移位指令:shr和sar

    • shr對無符號整數進行移位操作,右移位產生的空位用0填充。
    • sar指令根據整數符號位來判斷移位產生的空位的填充數,負數空位填1,正數空位填0。
    • 右移位移出的數據元素首先被移動到進位標誌,然後再移出去,這裡和左移一樣。
  • 邏輯操作指令

布爾邏輯操作:add、not、or、xor

and、or、xor指令格式一樣:
and src, dest
not指令使用單一操作數。
清空寄存器最高效的方式就是使用xor指令對寄存器和他本身進行異或操作。
  • 位測試指令:test src, dest

test指令最常見的用途是檢查EFLAGS寄存器中的標誌。