10 逻辑运算和移位指令
1 逻辑运算
| 指令 |
and |
or |
xor |
not |
test |
| C 算符 |
& |
\| |
^ |
~ |
|
| 解释 |
|
|
|
|
不保留结果的 and |
1.1 test 运算
Note
- 相当于进行一个
AND 运算,结果不会保留但会影响 flag
test 与 and 的关系相当于 cmp 和 sub 的关系
| test |
|---|
| mov ax, 1234h
test ax, 8000h ; ZF = 0, AX = 1234h
|
2 移位运算
| 指令 |
shl |
shr |
rol |
ror |
sal |
sar |
rcl |
rcr |
| C 算符 |
<< |
>> |
_rotl() |
_rotr() |
|
|
|
|
| 解释 |
|
|
循环左移 |
循环右移 |
算数左移 |
算数右移 |
带进位的逻辑左移 |
带进位的逻辑右移 |
2.1 循环移位指令 rol, ror
移位与 CF 的关系
Warning
CF 里保留的一定是最后移出去的一位,不论是什么移位指令
| shift - CF |
|---|
| mov ah, 0EFh ; 1110 1111, CF = ?
ror ah, 1 ; 1111 0111, CF = 1
|
| printf() |
|---|
| .386
data segment use16
abc dd 2147483647
data ends
code segment use16
assume cs:code, ds:data
main:
mov ax, seg abc
mov ds, ax
mov eax, abc ; 复习:编译后编程 mov eax, ds:[0],所以前面要先赋值
mov cx, 8
again:
rol eax, 4
push eax ; 为了暂时保护 eax 的值,保存到栈中
and eax, 0Fh ; 这时 and 运算清除了 eax 前面部分的内容
cmp al, 10
jb is_digit
is_alpha: // 16进制中的字母也可以打印
sub al, 10
add al, 'A'
jmp finish_4bits
is_digit:
add al, '0'
finish_4bits:
mov ah, 2
mov dl, al
int 21h
pop eax ; 表示从栈中恢复上次 push 时 eax 的值
sub cx, 1
jnz again ; jump if not zero
mov ah, 4Ch
int 21h
code ends
end main
|
使用 rol 指令,将 32-bit 数输出成 16 进制的格式
2.2 算数移位指令 sal, sar
sal 算数左移,其实等价于 shl
sar 算数右移,不等于 shr,因为有符号问题
| arithmetic shift |
|---|
| mov ah, 0FEh ; 1111 1110 = -2
sar ah, 1 ; 1111 1111 = -1
mov ah, 0FEh ; 1111 1110 = 254
shr ah, 1 ; 0111 1111 = 124
|
2.3 进位循环位移指令 rcl, rcr
rcl 带进位循环左移
rcr 带进位循环右移
- 每次移入
CF,移出的到 CF
| shift 1234ABCDh left 3 bit without 32-bit reg |
|---|
| ; method 1
mov ax, 0ABCDh
mov dx, 1234h
shl dx, 3
mov bx, ax
shl ax, 3
shr bx, 13
or dx, bx
; method 2 with rcl
mov ax, 0ABCDh
mov dx, 1234h
mov cx, 3
next:
shl ax, 1 ; 移到 CF
rcl dx, 1 ; CF 会补 DX 右侧的空洞
dec cx
jnq next
|