1. Shift 和 Rotate 指令
位移意味著在操作數(shù)內部按位左/右移動,其影響著OF和CF標志位。
1). 邏輯移動和算術移動
- 邏輯移動
將新創(chuàng)建的字節(jié)位填充0,
- 算術移動
新創(chuàng)建的字節(jié)位填充原位置上的數(shù)據(jù)克懊。
2). SHL 指令
SHL指令表示在目標操作數(shù)上邏輯左移洋丐,低位填充0豪诲。
- 格式
; 第一個是目標操作數(shù)吊圾,第二個是移動的位數(shù)
SHL destination,count
SHL reg,imm8
SHL mem,imm8
SHL reg,CL
SHL mem,CL
x86 處理器支持imm8的范圍在整型0—255之間碧信,另外,CL寄存器也可以包含移動的位數(shù)街夭。此格式同樣應用在SHR, SAL, SAR, ROR, ROL,
RCR 和RCL 指令。
示例:
mov bl,8Fh ; BL = 10001111b
shl bl,1 ; CF = 1, BL = 00011110b
mov al,10000000b
shl al,2 ; CF = 0, AL = 00000000b
- 按位乘
左移n位相當于操作數(shù)乘以2^n躏筏。
mov dl,5
shl dl,1
3). SHR 指令
SHR 指令表示在目標操作數(shù)上邏輯右移板丽,高位用0替換。
示例:
mov al,0D0h ; AL = 11010000b
shr al,1 ; AL = 01101000b, CF = 0
mov al,00000010b
shr al,2 ; AL = 00000000b, CF = 1
- 按位除
右移一個無符號整數(shù)n位相當于操作數(shù)除以2^n趁尼。
mov dl,32
shr dl,1
4). SAL 和 SAR 指令
- SAL
SAL 指令與SHL指令相同埃碱。SAL指令的每一位向高位移動,低位補0.
- SAR
SAR 指令移動后新的位置上填充原位置上的數(shù)字酥泞。
示例:
mov al,0F0h ; AL = 11110000b (-16)
sar al,1 ; AL = 11111000b (-8), CF = 0
- 符號除
有符號的操作數(shù)除以2砚殿,可以使用SAR指令。
mov dl,-128 ; DL = 10000000b
sar dl,3 ; DL = 11110000b
- AX符號擴展到EAX
AX包含一個有符號的整型芝囤,并將它擴展到EAX寄存器中似炎。
mov ax,-128 ; EAX = ????FF80h
shl eax,16 ; EAX = FF800000h
sar eax,16 ; EAX = FFFFFF80h
5). ROL 指令
ROL 指令指循環(huán)移動辛萍,即移出的一位補充到先增加的那個位置上。
示例:
mov al,40h ; AL = 01000000b
rol al,1 ; AL = 10000000b, CF = 0
rol al,1 ; AL = 00000001b, CF = 1
rol al,1 ; AL = 00000010b, CF = 0
- 多次旋轉
當循環(huán)位數(shù)大于1的時候羡藐,進位標志與最后一位相同
mov al,00100000b
rol al,3 ; CF = 1, AL = 00000001b
- 交換比特組
可以使用ROL交換高位和低位的字節(jié)贩毕。
mov al,26h
rol al,4 ; AL = 62h
6). ROR 指令
ROR 指令 每一位右移,并復制最低位到CF標志位和最高位仆嗦。
示例:
mov al,01h ; AL = 00000001b
ror al,1 ; AL = 10000000b, CF = 1
ror al,1 ; AL = 01000000b, CF = 0
- 多次旋轉
當使用旋轉位數(shù)大于1時辉阶,CF標志位與最后一次移動的位數(shù)值相同。
mov al,00000100b
ror al,3 ; AL = 10000000b, CF = 1
7). RCL 和 RCR 指令
RCL 指令向左移動每一位瘩扼,復制到CF標志位和最低位谆甜。
示例:
clc ; CF = 0 清空CF標志位
mov bl,88h ; CF,BL = 0 10001000b
rcl bl,1 ; CF,BL = 1 00010000b
rcl bl,1 ; CF,BL = 0 00100001b
- 從進位標志中恢復
RCL 可以恢復移動之前的CF標志位。
.data
testval BYTE 01101010b
.code
shr testval,1 ; shift LSB into Carry flag
jc exit ; exit if Carry flag set
rcl testval,1 ; else restore the number
- RCR 指令
RCR 指令向右移動每一位集绰,復制CF標志位到最高位规辱,將最低位復制到CF標志位。
示例:
stc ; CF = 1 設置CF標志位為1
mov ah,10h ; AH, CF = 00010000 1
rcr ah,1 ; AH, CF = 10001000 0
8). 符號溢出
移動或者旋轉一個有符號的整型時倒慧,符號位溢出后按摘,OF標志位被設置。
mov al,+127 ; AL = 01111111b
rol al,1 ; OF = 1, AL = 11111110b
9). SHLD / SHRD 指令
SHLD/SHRD 指令向左/右移動一個目標操作數(shù)指定的數(shù)字位數(shù)纫谅,新添加的位數(shù)由源操作數(shù)中的高/低位填充炫贤。格式如下:
SHLD/SHRD dest, source, count
SHLD/SHRD reg16,reg16,CL/imm8
SHLD/SHRD mem16,reg16,CL/imm8
SHLD/SHRD reg32,reg32,CL/imm8
SHLD/SHRD mem32,reg32,CL/imm8
- 示例1:
.data
wval WORD 9BA6h
.code
mov ax,0AC36h
shld wval,ax,4 ; wval = BA6Ah
- 示例2:
mov ax,234Bh
mov dx,7654h
shrd ax,dx,4 ; ax = 4234h
2. 移動和旋轉應用
1). 轉換多個DWORD
; 數(shù)組元素移位
INCLUDE Irvine32.inc
.data
ArraySize = 3
array BYTE ArraySize DUP(99h)
.code
main PROC
mov esi, 0
shr array[esi + 2], 1 ; 最高字節(jié)
rcr array[esi + 1], 1 ; 中間字節(jié)
rcr array[esi], 1 ; 低字節(jié)
call Crlf
call WaitMsg
exit
main ENDP
END
2). 二進制乘法
將某個數(shù)分解之后成為2的n次方,并將乘數(shù)依次與之相乘付秕,最后求和兰珍。例如:36可以分為25+22, 則10036 = 10025+100*22。
mov eax,100
mov ebx,eax
shl eax,5 ; multiply by 25
shl ebx,2 ; multiply by 22
add eax,ebx ; add the products
3). 顯示二進制位
共同的代碼程序將二進制整數(shù)轉換為ASCII碼字符串询吴,并將ASCII碼顯示掠河。
;---------------------------------------------------------
;
; Converts 32-bit binary integer to ASCII binary.
; Receives: EAX = binary integer, ESI points to buffer
; Returns: buffer filled with ASCII binary digits
;---------------------------------------------------------
BinToAsc PROC USES ecx, esi
mov ecx,32 ; number of bits in EAX
L1:
shl eax,1 ; shift high bit into Carry flag
mov BYTE PTR [esi],'0' ; choose 0 as default digit
jnc L2 ; if no Carry, jump to L2
mov BYTE PTR [esi],'1' ; else move 1 to buffer
L2:
inc esi ; next buffer position
loop L1 ; shift another bit to left
RET
BinToAsc ENDP
4). 提取文件日期
應用經常需要提取位串用于獲取時間。在MS-DOS中日期存儲在DX中猛计,其中0—4位代表天唠摹,5—8位代表月,9—15代表年奉瘤。
示例:
; 獲取天
mov al,dl ; make a copy of DL
and al,00011111b ; clear bits 5-7
mov day,al ; save in day
; 獲取月
mov ax,dx ; make a copy of DX
shr ax,5 ; shift right 5 bits
and al,00001111b ; clear bits 4-7
mov month,al ; save in month
; 獲取年
mov al,dh ; make a copy of DH
shr al,1 ; shift right one position
mov ah,0 ; clear AH to zeros
add ax,1980 ; year is relative to 1980
mov year,ax ; save in year
3. MUL 和 DIV 指令
在32位模式中勾拉,MUL和DIV 可以作用于32位,16位盗温,8位操作數(shù)藕赞。
在64為模式中,MUL和DIV指令作用于無符號整型中卖局,IMUL和IDIV指令作用于有符號整型中斧蜕。
1). MUL 指令
- 格式
MUL reg/mem8
MUL reg/mem16
MUL reg/mem32
; 示例1
mov al,5h
mov bl,10h
mul bl ; AX = 0050h, CF = 0
; 示例2
.data
val1 WORD 2000h
val2 WORD 0100h
.code
mov ax,val1 ; AX = 2000h
mul val2 ; DX:AX = 00200000h, CF = 1
; 示例3
mov eax,12345h
mov ebx,1000h
mul ebx ; EDX:EAX = 0000000012345000h, CF = 0
- 64位模式中的MUL
.data
multiplier QWORD 10h
.code
mov rax,0AABBBBCCCCDDDDh
mul multiplier ; RDX:RAX = 00000000000000000AABBBBCCCCDDDD0h
2). IMUL 指令
IMUL 指令表示有符號整數(shù)的乘法。
- 單操作數(shù)格式
IMUL reg/mem8 ; AX = AL * reg/mem8
IMUL reg/mem16 ; DX:AX = AX * reg/mem16
IMUL reg/mem32 ; EDX:EAX = EAX * reg/mem32
- 雙操作數(shù)格式
IMUL reg16,reg/mem16
IMUL reg16,imm8
IMUL reg16,imm16
IMUL reg32,reg/mem32
IMUL reg32,imm8
IMUL reg32,imm32
- 三操作數(shù)格式
IMUL reg16,reg/mem16,imm8
IMUL reg16,reg/mem16,imm16
IMUL reg32,reg/mem32,imm8
IMUL reg32,reg/mem32,imm32
如果符號位丟失砚偶,則需要設置OF和CF標志位批销。
- 64位模式下的IMUL
64位模式下洒闸,可以使用64位模式下MUL指令。在雙操作數(shù)格式下风钻,一個64位寄存器或者內存數(shù)乘以RDX顷蟀,產生一個128位有符號擴展的RDX:RAX。64位模式下三操作數(shù)格式也是可用的骡技。
; 雙操作數(shù)
mov rax,-4
mov rbx,4
imul rb ; RDX = 0FFFFFFFFFFFFFFFFh, RAX = -16
; 三操作數(shù)
.data
multiplicand QWORD -16
.code
imul rax, multiplicand, 4 ; RAX = FFFFFFFFFFFFFFC0 (-64)
示例:
; 單操作數(shù)
mov al,48
mov bl,4
imul bl ; AX = 00C0h, OF = 1
mov al,-4
mov bl,4
imul bl ; AX = FFF0h, OF = 0
; 雙操作數(shù)
.data
word1 SWORD 4
dword1 SDWORD 4
.code
mov ax,-16 ; AX = -16
mov bx,2 ; BX = 2
imul bx,ax ; BX = -32
imul bx,2 ; BX = -64
imul bx,word1 ; BX = -256
mov eax,-16 ; EAX = -16
mov ebx,2 ; EBX = 2
imul ebx,eax ; EBX = -32
imul ebx,2 ; EBX = -64
imul ebx,dword1 ; EBX = -256
mov ax,-32000
imul ax,2 ; OF = 1
; 三操作數(shù)
.data
word1 SWORD 4
dword1 SDWORD 4
.code
imul bx,word1,-16 ; BX = word1 * -16
imul ebx,dword1,-16 ; EBX = dword1 * -16
imul ebx,dword1,-2000000000 ; signed overflow!
3). 比較MUL/IMUL和移位的運行時間
; 比較MUL/IMUL和移位的運行時間
INCLUDE Irvine32.inc
.data
LOOP_COUNT = 0FFFFFFFFh
intval DWORD 5
startTime DWORD ?
shiftTime DWORD ?
mulTime DWORD ?
.code
main PROC
call GetMseconds ; get start time
mov startTime,eax
mov eax,intval ; multiply now
call mult_by_shifting
call GetMseconds ; get stop time
sub eax,startTime
call WriteDec ; display elapsed time
call Crlf
call GetMseconds ; get start time
mov startTime,eax
mov eax,intval ; multiply now
call mult_by_MUL
call GetMseconds ; get stop time
sub eax,startTime
call WriteDec ; display elapsed time
call Crlf
call WaitMsg
exit
main ENDP
;----------------------------------
; 使用SHL移位計算EAX*36
;----------------------------------
mult_by_shifting PROC USES eax
mov ecx, LOOP_COUNT
L1:
mov ebx, eax
shl eax, 5
shl eax, 2
add eax, ebx
LOOP L1
RET
mult_by_shifting ENDP
;----------------------------------
; 使用乘法計算EAX*36
;----------------------------------
mult_by_MUL PROC USES eax
mov ecx, LOOP_COUNT
L1:
mov ebx, 36
mul ebx
LOOP L1
RET
mult_by_MUL ENDP
END
4). DIV 指令
- 格式
DIV reg/mem8
DIV reg/mem16
DIV reg/mem32
- 示例
; 示例1
mov ax,0083h ; dividend
mov bl,2 ; divisor
div bl ; AL = 41h, AH = 01h
; 示例2
mov dx,0 ; clear dividend, high
mov ax,8003h ; dividend, low
mov cx,100h ; divisor
div cx ; AX = 0080h, DX = 0003h
5). 帶符號整數(shù)除法
有符號整數(shù)除法與無符號除法幾乎相同布朦,但有一個重要區(qū)別:除法必須在除法發(fā)生之前進行符號擴展囤萤。
.data
wordVal SWORD -101 ; 009Bh
.code
mov eax,0 ; EAX = 00000000h
mov ax,wordVal ; EAX = 0000009Bh (+155)
cwd ; EAX = FFFFFF9Bh (-101)
mov bx,2 ; EBX is the divisor
idiv bx ; divide EAX by BX
- 符號擴展指令 (CBW, CWD, CDQ)
CBW 指令(BYTE -> WORD)擴展符號位從AL到AH。CWD(WORD -> DWORD)擴展符號位AX到DX是趴。CDQ(DWORD -> QWORD)口占EAX到EDX涛舍。
; CBW 使用
.data
byteVal SBYTE -101 ; 9Bh
.code
mov al,byteVal ; AL = 9Bh
cbw ; AX = FF9Bh
; CWD 使用
.data
wordVal SWORD -101 ; FF9Bh
.code
mov ax,wordVal ; AX = FF9Bh
cwd
; CDQ 使用
.data
dwordVal SDWORD -101 ; FFFFFF9Bh
.code
mov eax,dwordVal
cdq
- IDIV 指令
IDIV 指令表示有符號除法,使用和DIV相同唆途。
.data
byteVal SBYTE -48 ; D0 hexadecimal
.code
mov al,byteVal ; lower half of dividend
cbw ; extend AL into AH
mov bl,+5 ; divisor
idiv bl ; AL = -9, AH = -3
- 除法溢出
mov ax,1000h
mov bl,10h
div bl ; AL cannot hold 100h
建議:使用32位除數(shù)和64位被除數(shù)來降低除法溢出條件的概率富雅。
6). 實現(xiàn)除法/乘法的算術表達式
; 示例表達式1: var4 = (var1 + var2) * var3
mov eax,var1
add eax,var2
mul var3 ; EAX = EAX * var3
jc tooBig ; unsigned overflow?
mov var4,eax
jmp next
tooBig: ; display error message
; 示例表達式2: var4 = (var1 * 5) / (var2 - 3)
mov eax,var1 ; left side
mov ebx,5
mul ebx ; EDX:EAX = product
mov ebx,var2 ; right side
sub ebx,3
div ebx ; final division
mov var4,eax
4. 擴展加和減
擴展加和減是添加和減去幾乎無限大小的數(shù)字的技術。
1). ADC 指令
ADC指令將源操作數(shù)和CF標志的內容添加到目標操作數(shù)肛搬。
- 格式
ADC reg,reg
ADC mem,reg
ADC reg,mem
ADC mem,imm
ADC reg,imm
示例:
mov dl,0
mov al,0FFh
add al,0FFh ; AL = FEh
adc dl,0 ; DL/AL = 01FEh
2). 擴展加示例
將數(shù)組中的數(shù)據(jù)一一對應相加没佑。
; 擴展加法示例:數(shù)組元素對應相加
INCLUDE Irvine32.inc
.data
op1 BYTE 34h,12h,98h,74h,06h,0A4h,0B2h,0A2h
op2 BYTE 02h,45h,23h,00h,00h,87h,10h,80h
sum BYTE 9 dup(0)
.code
main PROC
mov esi, OFFSET op1
mov edi, OFFSET op2
mov ebx, OFFSET sum
mov ecx, LENGTHOF op1
call Extended_Add
; 顯示和
mov esi, OFFSET sum
mov ecx, LENGTHOF sum
call Display_Sum
call Crlf
call WaitMsg
exit
main ENDP
;-------------------------------------------------
; 計算兩個字節(jié)數(shù)組之和
; Receives: ESI和EDI指向兩個整型,EBX指向一個存儲和的
; 變量温赔,ECX循環(huán)計數(shù)
; Returns: 無
;-------------------------------------------------
Extended_Add PROC
pushad
clc
L1:
mov al, [esi] ; 獲取第一個整數(shù)
adc al, [edi] ; 添加第二個整數(shù)
pushfd ; 保存CF標記位
mov [ebx], al ; 存儲和
add esi, 1 ; 指針指向下一個數(shù)
add edi, 1
add ebx, 1
popfd ; 恢復CF
LOOP L1 ; 循環(huán)
mov byte ptr [ebx], 0; 清除sum的高位
adc byte ptr [ebx], 0; 添加CF標記位
popad
RET
Extended_Add ENDP
Display_Sum PROC
pushad
; point to the last array element
add esi,ecx
sub esi,TYPE BYTE
mov ebx,TYPE BYTE
L1:
mov al,[esi] ; get an array byte
call WriteHexB ; display it
sub esi,TYPE BYTE ; point to previous byte
call Crlf
loop L1
popad
ret
Display_Sum ENDP
END
結果:0122C32B0674BB5736
, 數(shù)組對應元素的和蛤奢,在結果中從低位到高位顯示,最高位為符號位陶贼。
3). SBB 指令
SBB指令表示從目的操作數(shù)中減去源操作數(shù)和CF標志位啤贩。
mov edx,7 ; upper half
mov eax,1 ; lower half
sub eax,2 ; subtract 2
sbb edx,0 ; subtract upper half
5. ASCII 和未壓縮的十進制算法
- 四個處理指令
- ASCII 十進制 和 未解壓十進制
1). AAA 指令
mov ah,0
mov al,'8' ; AX = 0038h
add al,'2' ; AX = 006Ah
aaa ; AX = 0100h (ASCII adjust result)
or ax,3030h ; AX = 3130h = '10' (convert to ASCII)
- 使用AAA進行多字節(jié)相加
; ASCII 加法
; 字符串中ASCII算法
INCLUDE Irvine32.inc
DECIMAL_OFFSET = 5 ; 從右數(shù)字符串偏移
.data
decimal_one BYTE "100123456789765" ; 1001234567.89765
decimal_two BYTE "900402076502015" ; 9004020765.02015
sum BYTE (SIZEOF decimal_one + 1) DUP(0), 0
.code
main PROC
; 開始從最后一個數(shù)字的位置
mov esi, SIZEOF decimal_one - 1
mov edi, SIZEOF decimal_one
mov ecx, SIZEOF decimal_one
mov bh, 0 ; 設置CF為0
L1:
mov ah, 0 ; 加之前清空AH
mov al, decimal_one[esi] ; 獲取當前位置的數(shù)字
add al, bh ; 添加之前的進位
aaa ; 調整總和
mov bh, ah ; 存儲CF標志位
or bh, 30h ; 轉換ASCII
add al, decimal_two[esi] ; 添加第二個數(shù)
aaa ; 調整總和
or bh, ah ; 或CF標志位
or bh, 30h ; 轉換為ASCII碼
or al, 30h ; 轉換al為ASCII
mov sum[edi], al ; 存儲和
dec esi ; 移動到下一位
dec edi
LOOP L1
mov sum[edi], bh ; 存儲進位
; 顯示總和字符串
mov edx, OFFSET sum
call WriteString
call Crlf
call WaitMsg
exit
main ENDP
END
2). AAS 指令
.data
val1 BYTE '8'
val2 BYTE '9'
.code
mov ah,0
mov al,val1 ; AX = 0038h
sub al,val2 ; AX = 00FFh
aas ; AX = FF09h
pushf ; save the Carry flag
or al,30h ; AX = FF39h
popf ; restore the Carry flag
此處8 - 9 之后,AH減1變?yōu)镕Fh, AL變?yōu)?9h, 可理解為18 - 9拜秧,即個位為9痹屹,向前借了一位。
3). AAM 指令
.data
AscVal BYTE 05h,06h
.code
mov bl,ascVal ; first operand
mov al,[ascVal+1] ; second operand
mul bl ; AX = 001Eh
aam ; AX = 0300h , or 3030h
4). AAD 指令
.data
quotient BYTE ?
remainder BYTE ?
.code
mov ax,0307h ; dividend
aad ; AX = 0025h, or 3030h
mov bl,5 ; divisor
div bl ; AX = 0207h
mov quotient,al
mov remainder,ah
6. 壓縮十進制算術
涉及到兩個指令:DAA (decimal adjust after addition) 與 DAS (decimal adjust after subtraction)枉氮。壓縮十進制算術中無乘法和相關指令志衍。
1). DAA
; 壓縮加法
; 壓縮十進制加法
INCLUDE Irvine32.inc
.data
packed_1 WORD 4536h
packed_2 WORD 7207h
sum DWORD ?
.code
main PROC
; 初始化總和和序號
mov sum, 0
mov esi, 0
; 添加低字節(jié)
mov al, BYTE PTR packed_1[esi]
add al, BYTE PTR packed_2[esi]
daa
mov BYTE PTR sum[esi], al
; 添加高字節(jié),包含CF標志位
inc esi
mov al, BYTE PTR packed_1[esi]
adc al, BYTE PTR packed_2[esi]
daa
mov BYTE PTR sum[esi], al
; 添加CF標志位
inc esi
mov al, 0
adc al, 0
mov BYTE PTR sum[esi], al
; 十六進制格式顯示
mov eax, sum
call WriteHex
call Crlf
call WaitMsg
exit
main ENDP
END
2). DAS
mov bl,48h
mov al,85h
sub al,bl ; AL = 3Dh
das ; AL = 37h (adjusted result)