Skip to content

10 逻辑运算和移位指令

1 逻辑运算#

指令 and or xor not test
C 算符 & \| ^ ~
解释 不保留结果的 and

1.1 test 运算#

Note

  • 相当于进行一个 AND 运算,结果不会保留但会影响 flag
  • testand 的关系相当于 cmpsub 的关系
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
1
2
3
4
5
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

Comments