文章目录
🌟 SBB指令的"生活小剧场"
想象你在玩一个借东西的游戏:
基本规则:每次减法都要多扣1(如果上次借钱没还清)
- 就像你找朋友A借了1块钱(CF=1),下次还钱时除了该还的,还得把这1块补上
操作码就像点菜单:
8位套餐: SBB AL,5 # 用AL寄存器减5 16位套餐: SBB AX,BX # 用AX减BX寄存器 32位豪华餐:SBB [存款],100 # 直接减内存里的钱
两个严禁事项:
- ❌ 不能同时操作两个内存数(就像不能同时修改两个账本)
- ❌ 不能跨尺寸操作(8位和32位不能直接混用)
🎯 四种经典使用场景
日常零钱计算(8位)
mov al, 50 # 钱包有50元 sbb al, 30 # 花30元,如果之前欠1元(CF=1),实际扣31元
年终奖计算(16位)
mov ax, 20000 # 年终奖2万 sbb ax, 3000 # 扣税3千,如果上月预支了1千(CF=1),总共扣4千
房贷计算(32位)
mov esi, 5000000 # 贷款500万 sbb esi, 10000 # 本月还款1万,如果逾期要罚1千(CF=1),实际还1万1
土豪的64位操作
; 先处理低32位(零钱部分) sub eax, ecx # 普通减法 ; 再处理高32位(巨额部分) sbb edx, ebx # 记得把刚才的借位算上!
💡 重点提示板
标志位 | 含义 | 现实比喻 |
---|---|---|
CF | 借位标志 | 就像记账本上的"欠1元"小纸条 |
OF | 数值爆炸警告 | 计算器显示"E"的错误提示 |
SF | 结果正负 | 余额前面的±号 |
ZF | 是否归零 | 钱包空空如也的叮当响 |
🚀 什么时候用SBB?
- 需要处理"上次计算有借位"时(就像连续记账)
- 做大数运算(超过32位的加减法)
- 精确控制计算流程时(金融/密码学相关代码)
下次看到SBB,就想象成:
“这次减法要把上次欠的1块钱也还上哦~” 💰
这样的解释是不是更有温度呢?想继续深入了解哪个部分,我随时可以展开讲~
演示了SBB(带借位减法)指令的使用
以下是修改后的代码,演示了SBB(带借位减法)指令的使用,并包含详细的注释和标志位说明:
; 设置处理器模式和内存模型
.586 ; 使用 586 指令集
.model flat, stdcall ; 平坦内存模型,stdcall 调用约定
option casemap:none ; 区分大小写
; 引入库文件
includelib kernel32.lib ; Windows API 库
includelib msvcrt.lib ; C 运行时库
.data ; 数据段定义
; 测试数据
byteVal db 80h ; -128(有符号最小值)
wordVal dw 0001h ; 1
dwordVal dd 80000000h ; -2147483648(有符号最小值)
; 结果存储
byteResult db ?
wordResult dw ?
dwordResult dd ?
; 标志位检测
CF_flag db ? ; 进位/借位标志
OF_flag db ? ; 溢出标志
SF_flag db ? ; 符号标志
ZF_flag db ? ; 零标志
.code ; 代码段
main proc
; ---------------------------
; 1. 8位SBB指令演示(带借位减法)
; ---------------------------
stc ; 设置CF=1(模拟前一步操作有借位)
mov al, byteVal ; AL = 80h (-128)
sbb al, 1 ; AL = 80h - 1 - 1 = 7Eh (126)
mov byteResult, al ; 存储结果
; 标志位变化:
; CF=0(无符号:0x80→0x7E 不需要借位)
; OF=1(有符号溢出:-128 -1 -1 →126)
; SF=0(结果为正)
; ZF=0(结果非零)
; ---------------------------
; 2. 16位SBB指令演示(寄存器减内存)
; ---------------------------
clc ; 清除CF=0(模拟前一步无借位)
mov ax, 5 ; AX = 5
sbb ax, wordVal ; AX = 5 - 1 - 0 = 4
mov wordResult, ax ; 存储结果
; 标志位变化:
; CF=0(无借位)
; OF=0(无溢出)
; SF=0(结果非负)
; ZF=0(结果非零)
; ---------------------------
; 3. 32位SBB指令演示(内存减立即数)
; ---------------------------
stc ; 设置CF=1
sbb dwordVal, 1 ; dwordVal = 80000000h - 1 - 1 = 7FFFFFFEh
mov eax, dwordVal
mov dwordResult, eax
; 标志位变化:
; CF=0(无符号借位)
; OF=1(有符号溢出:-2147483648 -1 -1 = 2147483646)
; SF=0(结果为正)
; ZF=0(结果非零)
; ---------------------------
; 4. 多精度减法演示(64位减法)
; ---------------------------
; 假设 EDX:EAX = 00000001:00000000h (4294967296)
; 减去 EBX:ECX = 00000000:00000001h (1)
mov edx, 1
mov eax, 0
mov ebx, 0
mov ecx, 1
sub eax, ecx ; 低32位减法
sbb edx, ebx ; 高32位带借位减法
; 结果 EDX:EAX = 00000000:FFFFFFFFh (4294967295)
; ---------------------------
; 5. 带符号扩展的SBB
; ---------------------------
mov cx, 100h ; CX = 256
stc ; CF=1
sbb cx, 0FFh ; CX = 100h - FFh - 1 = 0 (256-255-1)
; 标志位变化:
; CF=0(无借位)
; OF=0(无溢出)
; SF=0(结果非负)
; ZF=1(结果为零)
; ---------------------------
; 标志位存储演示
; ---------------------------
setc CF_flag ; 存储进位标志(最后操作后应为0)
seto OF_flag ; 存储溢出标志(最后操作后应为0)
sets SF_flag ; 存储符号标志(最后操作后应为0)
setz ZF_flag ; 存储零标志(最后操作后应为1)
; ---------------------------
; 程序退出
; ---------------------------
xor eax, eax ; 返回码 0
ret
main endp
end main
关键修改说明:
SBB指令演示:
- 所有减法操作改为SBB指令,并配合STC/CLC设置CF标志
- 展示了8位、16位和32位操作数的使用
多精度减法:
- 新增64位减法示例(使用32位寄存器组合)
- 先使用SUB处理低32位,再用SBB处理高32位
标志位变化:
- 每个操作后添加详细的标志位说明
- 最后使用SETcc指令存储标志位状态
操作类型:
- 寄存器-立即数
- 寄存器-内存
- 内存-立即数
- 多寄存器操作
这个修改版清晰地展示了SBB指令在各种场景下的应用,特别是如何处理借位标志(CF)在多精度运算中的传递。
以下是针对代码中每种 SBB(带借位减法) 场景的详细解释,包括操作逻辑、结果和标志位变化:
1. 8位SBB指令演示(带借位减法)
stc ; 设置 CF=1(模拟前一步操作有借位)
mov al, byteVal ; AL = 80h (-128)
sbb al, 1 ; AL = 80h - 1 - 1 = 7Eh (126)
- 操作逻辑:
AL = AL - imm8 - CF = 80h - 1 - 1 = 7Eh
- 数值计算:
-128 - 1 - 1 = -130
,但8位有符号范围为-128~127
,结果截断为7Eh
(126)。
- 数值计算:
- 标志位:
- CF=0:无符号运算未借位(
0x80 → 0x7E
不需要借位)。 - OF=1:有符号溢出(
-128 - 2
本应为-130
,但结果126
超出8位有符号范围)。 - SF=0:结果最高位为
0
(正数)。 - ZF=0:结果非零。
- CF=0:无符号运算未借位(
2. 16位SBB指令演示(寄存器减内存)
clc ; 清除 CF=0
mov ax, 5 ; AX = 5
sbb ax, wordVal ; AX = 5 - 1 - 0 = 4
- 操作逻辑:
AX = AX - [wordVal] - CF = 5 - 1 - 0 = 4
- 直接减法,无特殊溢出或借位。
- 标志位:
- CF=0:无借位。
- OF=0:无有符号溢出(
5 - 1 = 4
是合法值)。 - SF=0:结果为正。
- ZF=0:结果非零。
3. 32位SBB指令演示(内存减立即数)
stc ; 设置 CF=1
sbb dwordVal, 1 ; dwordVal = 80000000h - 1 - 1 = 7FFFFFFEh
- 操作逻辑:
[dwordVal] = [dwordVal] - imm32 - CF = 80000000h - 1 - 1 = 7FFFFFFEh
- 数值计算:
-2147483648 - 1 - 1 = -2147483650
,但32位有符号范围为-2147483648~2147483647
,结果截断为7FFFFFFEh
(2147483646)。
- 数值计算:
- 标志位:
- CF=0:无符号运算未借位(从
80000000h
减到7FFFFFFEh
未跨越边界)。 - OF=1:有符号溢出(结果应为
-2147483650
,但实际得到2147483646
)。 - SF=0:结果最高位为
0
(正数)。 - ZF=0:结果非零。
- CF=0:无符号运算未借位(从
4. 多精度减法演示(64位减法)
mov edx, 1 ; 高32位 = 1
mov eax, 0 ; 低32位 = 0
mov ebx, 0 ; 高32位 = 0
mov ecx, 1 ; 低32位 = 1
sub eax, ecx ; 低32位减法:0 - 1 = FFFFFFFFh (CF=1)
sbb edx, ebx ; 高32位带借位:1 - 0 - 1 = 0
- 操作逻辑:
计算EDX:EAX - EBX:ECX
(即1:00000000h - 0:00000001h
):- 低32位:
SUB EAX, ECX
→0 - 1 = FFFFFFFFh
,设置CF=1
。 - 高32位:
SBB EDX, EBX
→1 - 0 - 1 = 0
。
- 最终结果:
EDX:EAX = 00000000:FFFFFFFFh
(即4294967295
)。
- 低32位:
- 标志位:
- CF=0:高32位未借位。
- OF=0:结果在64位范围内合法。
- SF=0:高32位为
0
(非负数)。 - ZF=0:结果非零(低32位为
FFFFFFFFh
)。
5. 带符号扩展的SBB(16位减8位立即数)
mov cx, 100h ; CX = 256
stc ; CF=1
sbb cx, 0FFh ; CX = 100h - FFh - 1 = 0 (256 - 255 - 1)
- 操作逻辑:
CX = CX - (符号扩展的 0FFh) - CF = 100h - FFFFh - 1
- 实际计算时,
0FFh
被符号扩展为FFFFh
(-1),因此:
256 - (-1) - 1 = 256
→ 截断为0000h
(因16位寄存器)。
- 实际计算时,
- 标志位:
- CF=0:无借位(
100h - FFFFh
需要借位,但减1
后抵消)。 - OF=0:无溢出(
256 - 0 = 256
超出16位无符号范围,但实际结果为0
)。 - SF=0:结果非负。
- ZF=1:结果为零。
- CF=0:无借位(
标志位存储结果
setc CF_flag ; 存储 CF(最后操作后 CF=0)
seto OF_flag ; 存储 OF(最后操作后 OF=0)
sets SF_flag ; 存储 SF(最后操作后 SF=0)
setz ZF_flag ; 存储 ZF(最后操作后 ZF=1)
- 最终标志位状态:
CF_flag = 0
OF_flag = 0
SF_flag = 0
ZF_flag = 1
关键总结
- SBB与SUB的区别:
SBB会额外减去进位标志(CF),用于处理多精度运算中的借位传递。 - 多精度减法:
低位数用SUB
,高位数用SBB
,通过CF传递借位。 - 标志位意义:
- CF:无符号运算的借位。
- OF:有符号运算的溢出。
- SF/ZF:结果的符号和零状态。
通过这5个场景,可以全面理解SBB在8/16/32位操作、内存/寄存器操作、多精度运算中的应用!
以下是优化排版后的SBB指令说明表格:
SBB - 带借位整数减法指令集
操作码 | 指令格式 | 说明 |
---|---|---|
8位操作 | ||
1C ib |
SBB AL, imm8 |
AL ← AL - imm8 - CF |
80 /3 ib |
SBB r/m8, imm8 |
r/m8 ← r/m8 - imm8 - CF |
18 /r |
SBB r/m8, r8 |
r/m8 ← r/m8 - r8 - CF |
1A /r |
SBB r8, r/m8 |
r8 ← r8 - r/m8 - CF |
16位操作 | ||
1D iw |
SBB AX, imm16 |
AX ← AX - imm16 - CF |
81 /3 iw |
SBB r/m16, imm16 |
r/m16 ← r/m16 - imm16 - CF |
83 /3 ib |
SBB r/m16, imm8 |
r/m16 ← r/m16 - (符号扩展imm8) - CF |
19 /r |
SBB r/m16, r16 |
r/m16 ← r/m16 - r16 - CF |
1B /r |
SBB r16, r/m16 |
r16 ← r16 - r/m16 - CF |
32位操作 | ||
1D id |
SBB EAX, imm32 |
EAX ← EAX - imm32 - CF |
81 /3 id |
SBB r/m32, imm32 |
r/m32 ← r/m32 - imm32 - CF |
83 /3 ib |
SBB r/m32, imm8 |
r/m32 ← r/m32 - (符号扩展imm8) - CF |
19 /r |
SBB r/m32, r32 |
r/m32 ← r/m32 - r32 - CF |
1B /r |
SBB r32, r/m32 |
r32 ← r32 - r/m32 - CF |
关键说明
操作逻辑:
DEST ← DEST - (SRC + CF)
操作数限制:
- 不允许两个操作数同时为内存操作数。
立即数处理:
- 立即数会被符号扩展到目标操作数的长度(如
SBB r/m32, imm8
中imm8扩展为32位)。
- 立即数会被符号扩展到目标操作数的长度(如
标志位影响:
- OF/SF/ZF/AF/PF/CF 根据结果设置:
- CF 表示无符号运算的借位。
- OF 表示有符号运算的溢出。
- SF 表示有符号结果的符号(负数时置1)。
- OF/SF/ZF/AF/PF/CF 根据结果设置:
典型用途:
- 用于多精度减法(如64位减法需拆分为两个32位操作:
SUB
低32位后接SBB
高32位)。
- 用于多精度减法(如64位减法需拆分为两个32位操作:
优化后的表格采用分层结构,突出不同位宽的操作,并合并重复说明项,便于快速查阅。