1. Shift 和 Rotate 指令
位移意味着在操作数内部按位左/右移动,其影响着OF和CF标志位。
Shift and Rotate Instructions.png1). 逻辑移动和算术移动
- 逻辑移动
将新创建的字节位填充0,
- 算术移动
新创建的字节位填充原位置上的数据。
2). SHL 指令
SHL指令表示在目标操作数上逻辑左移,低位填充0。
SHL.png- 格式
; 第一个是目标操作数,第二个是移动的位数
SHL destination,count
SHL reg,imm8
SHL mem,imm8
SHL reg,CL
SHL mem,CL
x86 处理器支持imm8的范围在整型0—255之间,另外,CL寄存器也可以包含移动的位数。此格式同样应用在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位相当于操作数乘以2^n。
mov dl,5
shl dl,1
Bitwise Multiplication.png
3). SHR 指令
SHR 指令表示在目标操作数上逻辑右移,高位用0替换。
SHR.png示例:
mov al,0D0h ; AL = 11010000b
shr al,1 ; AL = 01101000b, CF = 0
mov al,00000010b
shr al,2 ; AL = 00000000b, CF = 1
- 按位除
右移一个无符号整数n位相当于操作数除以2^n。
mov dl,32
shr dl,1
Bitwise Division.png
4). SAL 和 SAR 指令
- SAL
SAL 指令与SHL指令相同。SAL指令的每一位向高位移动,低位补0.
- SAR
SAR 指令移动后新的位置上填充原位置上的数字。
示例:
mov al,0F0h ; AL = 11110000b (-16)
sar al,1 ; AL = 11111000b (-8), CF = 0
- 符号除
有符号的操作数除以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 指令指循环移动,即移出的一位补充到先增加的那个位置上。
SHL.png示例:
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
- 多次旋转
当循环位数大于1的时候,进位标志与最后一位相同
mov al,00100000b
rol al,3 ; CF = 1, AL = 00000001b
- 交换比特组
可以使用ROL交换高位和低位的字节。
mov al,26h
rol al,4 ; AL = 62h
6). ROR 指令
ROR 指令 每一位右移,并复制最低位到CF标志位和最高位。
ROR.png示例:
mov al,01h ; AL = 00000001b
ror al,1 ; AL = 10000000b, CF = 1
ror al,1 ; AL = 01000000b, CF = 0
- 多次旋转
当使用旋转位数大于1时,CF标志位与最后一次移动的位数值相同。
mov al,00000100b
ror al,3 ; AL = 10000000b, CF = 1
7). RCL 和 RCR 指令
RCL 指令向左移动每一位,复制到CF标志位和最低位。
RCL.png示例:
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 指令向左/右移动一个目标操作数指定的数字位数,新添加的位数由源操作数中的高/低位填充。格式如下:
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
SHLD.png
SHRD.png
- 示例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
; 数组元素移位
INCLUDE Irvine32.inc
.data
ArraySize = 3
array BYTE ArraySize DUP(99h)
.code
main PROC
mov esi, 0
shr array[esi + 2], 1 ; 最高字节
rcr array[esi + 1], 1 ; 中间字节
rcr array[esi], 1 ; 低字节
call Crlf
call WaitMsg
exit
main ENDP
END
2). 二进制乘法
将某个数分解之后成为2的n次方,并将乘数依次与之相乘,最后求和。例如: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). 显示二进制位
共同的代码程序将二进制整数转换为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代表年。
Extracting File Date Fields.png示例:
; 获取天
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位操作数。
在64为模式中,MUL和DIV指令作用于无符号整型中,IMUL和IDIV指令作用于有符号整型中。
1). MUL 指令
- 格式
MUL reg/mem8
MUL reg/mem16
MUL reg/mem32
MUL Operands.png
; 示例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 指令表示有符号整数的乘法。
- 单操作数格式
IMUL reg/mem8 ; AX = AL * reg/mem8
IMUL reg/mem16 ; DX:AX = AX * reg/mem16
IMUL reg/mem32 ; EDX:EAX = EAX * reg/mem32
- 双操作数格式
IMUL reg16,reg/mem16
IMUL reg16,imm8
IMUL reg16,imm16
IMUL reg32,reg/mem32
IMUL reg32,imm8
IMUL reg32,imm32
- 三操作数格式
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指令。在双操作数格式下,一个64位寄存器或者内存数乘以RDX,产生一个128位有符号扩展的RDX:RAX。64位模式下三操作数格式也是可用的。
; 双操作数
mov rax,-4
mov rbx,4
imul rb ; RDX = 0FFFFFFFFFFFFFFFFh, RAX = -16
; 三操作数
.data
multiplicand QWORD -16
.code
imul rax, multiplicand, 4 ; RAX = FFFFFFFFFFFFFFC0 (-64)
示例:
; 单操作数
mov al,48
mov bl,4
imul bl ; AX = 00C0h, OF = 1
mov al,-4
mov bl,4
imul bl ; AX = FFF0h, OF = 0
; 双操作数
.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
; 三操作数
.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
效果.png
4). DIV 指令
- 格式
DIV reg/mem8
DIV reg/mem16
DIV reg/mem32
被除数、除数、商和余数关系.png
- 示例
; 示例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). 带符号整数除法
有符号整数除法与无符号除法几乎相同,但有一个重要区别:除法必须在除法发生之前进行符号扩展。
.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位除数和64位被除数来降低除法溢出条件的概率。
6). 实现除法/乘法的算术表达式
; 示例表达式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. 扩展加和减
扩展加和减是添加和减去几乎无限大小的数字的技术。
1). ADC 指令
ADC指令将源操作数和CF标志的内容添加到目标操作数。
- 格式
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
效果.png
2). 扩展加示例
将数组中的数据一一对应相加。
; 扩展加法示例:数组元素对应相加
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
;-------------------------------------------------
; 计算两个字节数组之和
; Receives: ESI和EDI指向两个整型,EBX指向一个存储和的
; 变量,ECX循环计数
; Returns: 无
;-------------------------------------------------
Extended_Add PROC
pushad
clc
L1:
mov al, [esi] ; 获取第一个整数
adc al, [edi] ; 添加第二个整数
pushfd ; 保存CF标记位
mov [ebx], al ; 存储和
add esi, 1 ; 指针指向下一个数
add edi, 1
add ebx, 1
popfd ; 恢复CF
LOOP L1 ; 循环
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
, 数组对应元素的和,在结果中从低位到高位显示,最高位为符号位。
3). SBB 指令
SBB指令表示从目的操作数中减去源操作数和CF标志位。
mov edx,7 ; upper half
mov eax,1 ; lower half
sub eax,2 ; subtract 2
sbb edx,0 ; subtract upper half
Subtracting from a 64-bit integer using SBB.png
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进行多字节相加
; ASCII 加法
; 字符串中ASCII算法
INCLUDE Irvine32.inc
DECIMAL_OFFSET = 5 ; 从右数字符串偏移
.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
; 开始从最后一个数字的位置
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] ; 获取当前位置的数字
add al, bh ; 添加之前的进位
aaa ; 调整总和
mov bh, ah ; 存储CF标志位
or bh, 30h ; 转换ASCII
add al, decimal_two[esi] ; 添加第二个数
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
效果.png
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变为FFh, AL变为39h, 可理解为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
; 添加低字节
mov al, BYTE PTR packed_1[esi]
add al, BYTE PTR packed_2[esi]
daa
mov BYTE PTR sum[esi], al
; 添加高字节,包含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
AddPacked.png
2). DAS
mov bl,48h
mov al,85h
sub al,bl ; AL = 3Dh
das ; AL = 37h (adjusted result)
网友评论