汇编与调试第4周复习笔记(含老师样例代码)
1. 本周学习目标
- 掌握有符号与无符号运算在比较、乘除中的区别
- 熟悉位运算、移位、循环移位的常用场景
- 会写 32 位整数转 16 进制/2 进制输出程序
2. 知识点整理
2.1 算术运算
- add/sub:普通加减
- mul:无符号乘法
- imul:有符号乘法
- div:无符号除法
- idiv:有符号除法
关键区别:
- signed 与 unsigned 的解释方式不同
- 溢出与截断时要观察 OF、CF 与结果寄存器高位
2.2 比较与跳转
有符号跳转:jg、jl、jge、jle、je、jne
无符号跳转:ja、jb、jae、jbe、je、jne
同一比特模式在不同语义下可得相反结论(例如 FFFFh 可看作 -1 或 65535)。
2.3 位运算与移位
- and/or/xor/not
- shl/shr/sar
- rol/ror/rcl/rcr
应用:
- 掩码清位、置位、翻转
- 抽取 bit/半字节用于进制转换
3. 老师样例代码(第4周)
3.1 1.asm(知识点总讲义)
asm
1. 算术运算
add sub imul/mul idiv/div
mov ax, 2
mov bx, 3
imul ax, bx ; ax = ax * bx = 2*3 = 0006h
; OF=0, CF=0
mov ax, 1234h
mov bx, 100h
imul ax, bx ; ax=123400h 无法保存
; ax=3400h, OF=1, CF=1
mov ax, 2
mov bx, 3
mul bx ; ax * bx = dx、ax
; dx=0000h, ax=0006h
mov dx, -1
mov ax, -5 ; dx、ax = 0FFFFFFFBh = -5
mov bx, 2
idiv bx ; dx、ax / bx
2. 关系运算
先用cmp比较,再跟随j开头的条件跳转指令实现分支
(1) 跟符号数比较相关的跳转指令
jg jl jge jle je jne
(2) 跟非符号数比较相关的跳转指令
ja jb jae jbe je jne
mov ax, 0FFFFh ; -1
mov bx, 1
cmp ax, bx
jl ax_is_less_than_bx ; 会发生跳转
mov ax, 0FFFFh ; 65535
mov bx, 1
cmp ax, bx
jb ax_is_below_bx ; 不会发生跳转
mov cx, 0
sub cx, 1; cx=0FFFFh=65535
cmp cx, 0
jb done ; 不会跳转, 因为65535 > 0
3. 二进制运算
C语言的二进制运算符: & | ^ ~ << >>
与 或 异或 非 左移 右移
循环左移库函数 _rotl()
循环右移库函数 _rotr()
汇编语言的二进制运算指令:
and or xor not shl/sal shr/sar
循环左移指令rol, 循环左移指令ror
带进位的循环左移指令rcl, 带进位的循环右移指令rcr
mov ah, 10110110B; 或写成 mov ah, 0B6h
; B是二进制常数的后缀
mov bh, 01011010B
and ah, bh ; ah = ah & bh = 00010010B = 12h
10110110
01011010 and)
-------------
00010010
mov ah, 10110110B; 或写成 mov ah, 0B6h
; B是二进制常数的后缀
mov bh, 01011010B
or ah, bh ; ah = ah | bh = 11111110B = 0FEh
10110110
01011010 or)
-------------
11111110
mov ah, 10110110B; 或写成 mov ah, 0B6h
; B是二进制常数的后缀
mov bh, 01011010B
xor ah, bh ; ah = ah ^ bh = 11101100B = 0ECh
10110110
01011010 xor)
-------------
11101100
mov ah, 10110110B; 或写成 mov ah, 0B6h
; B是二进制常数的后缀
not ah ; ah = 01001001B = 49h
10110110 not)
-------------
01001001
mov ah, 3
shl ah, 1 ; 左移1位, shl: shift left 逻辑左移
0000 0011 ; 移位前
0000 0110 ; 移位后, 移出去的原最高位自动进入CF
; 本例中, CF=0
; 左移1位相当于乘以2
mov ah, 3
shr ah, 1 ; 右移1位, shl: shift right 逻辑右移
; 右移1位相当于除以2
0000 0011 ; 移位前
0000 0001 ; 移位后, 移出去的原最低位自动进入CF
; 本例中, CF=1
?011 011? ==> 0011 0110 ; 最高位及最低位清零,其余位不变
设此数在ah中
and ah, 01111110B ; 01111110B 是mask(掩码), 起过滤作用
?011 011?
0111 1110 and)
---------------
0011 0110
?011 011? ==> 1011 0111 ; 最高位及最低位置1,其余位不变
设此数在ah中
or ah, 10000001B ; 10000001B 是mask(掩码), 起过滤作用
?011 011?
1000 0001 or)
---------------
1011 0111
1011 0110 ==> 0011 0111 ; 最高位及最低位反转,其余位不变
设此数在ah中
xor ah, 10000001B ; 10000001B 是mask(掩码), 起过滤作用
1011 0110
1000 0001 xor)
---------------
0011 0111
异或的可逆性
设z = x ^ y,则一定有:
x = z ^ y 且
y = z ^ x
举例:
x=1011 0110B
y=1100 0011B xor)
z=0111 0101B
循环左移
mov al, 10110110B
rol al, 1; 把AL循环左移1位, rol:rotate left
; al=01101101B, CF=1
mov eax, 12345678h
rol eax, 4
0001 0010 0011 0100 0101 0110 0111 1000; 移位前
0010 0011 0100 0101 0110 0111 1000 0001; 移位后3.2 2.asm(32位整数转16进制输出)
asm
;把32位整数转化成16进制格式输出
.386
code segment use16
assume cs:code
main:
mov eax, 12345678h
mov cx, 8
again:
rol eax, 4 ; eax = 23456781h
;push eax ; 把eax的值压入堆栈
mov ebx, eax ; ebx = eax, 备份eax的值到ebx中
and eax, 1111B; 或写成 and eax, 0Fh
cmp eax, 10
jl is_digit
is_alpha:
sub eax, 10
add eax, 'A'
jmp output
is_digit:
add eax, '0'
output:
mov ah, 2
mov dl, al ; 不能写成mov dl, eax; 因为操作数必须等宽
int 21h
mov eax, ebx ; 恢复eax的值
;pop eax ; 从堆栈中弹出eax即恢复eax
sub cx, 1
jnz again
mov ah, 4Ch
mov al, 0
int 21h
code ends
end main3.3 3.asm(32位整数转二进制输出)
asm
;把32位整数转化成二进制格式输出
.386
code segment use16
assume cs:code
main:
mov eax, 12345678h
mov cx, 32
again:
rol eax, 1 ; eax = 23456781h
;push eax ; 把eax的值压入堆栈
mov ebx, eax ; ebx = eax, 备份eax的值到ebx中
and eax, 1
add eax, '0'
output:
mov ah, 2
mov dl, al ; 不能写成mov dl, eax; 因为操作数必须等宽
int 21h
mov eax, ebx ; 恢复eax的值
;pop eax ; 从堆栈中弹出eax即恢复eax
sub cx, 1
jnz again
mov ah, 4Ch
mov al, 0
int 21h
code ends
end main3.4 imul.asm(有符号乘法补充)
asm
.386
code segment use16
assume cs:code
main:
mov ax, 1234h
mov bx, 100h
imul ax, bx
mov ax, 1234h
mov bx, 100h
imul bx
mov ax, -2
mov bx, 2
imul bx
code ends
end main3.5 idiv.asm(有符号除法补充)
asm
.386
code segment use16
assume cs:code
main:
mov dx, -1
mov ax, -5 ; dx、ax = 0FFFFFFFBh = -5
mov bx, 2
idiv bx ; dx、ax / bx
; ax=0FFFEh=-2, dx=0FFFFh=-1
code ends
end main4. 本周易错点清单
- 有符号比较误用 jb/ja
- 无符号比较误用 jl/jg
- 抽 bit/半字节时忘记备份原寄存器
- mov dl, eax 这样的宽度不匹配写法
- 只会背指令,不会结合场景(掩码、输出)
5. 复习建议
- 把 1.asm 里的每条位运算都手算一遍二进制结果。
- 口算 FFFFh 与 1 比较时,signed/unsigned 两种结论。
- 重新默写 2.asm:不用看代码也能写出 16 进制输出流程。