HoRain云--汇编语言算术指令完全指南

🎬 HoRain云小助手:个人主页
🔥 个人专栏: 《Linux 系列教程》《c语言教程》
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
专栏介绍
|
专栏名称 |
专栏介绍 |
|
本专栏主要撰写C干货内容和编程技巧,让大家从底层了解C,把更多的知识由抽象到简单通俗易懂。 |
|
|
本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘,一起解密网络协议在运行中协议的基本运行机制! |
|
|
全面深入解析 docker 容器,从基础到进阶,涵盖原理、操作、实践案例,助您精通 docker。 |
|
|
本专栏主要撰写Linux干货内容,从基础到进阶,知识由抽象到简单通俗易懂,帮你从新手小白到扫地僧。 |
|
|
本专栏着重撰写Python相关的干货内容与编程技巧,助力大家从底层去认识Python,将更多复杂的知识由抽象转化为简单易懂的内容。 |
|
|
本专栏主要是发布一些考试和练习题库(涵盖软考、HCIE、HRCE、CCNA等) |
目录

📊 汇编语言 - 算术指令完全指南
算术指令是汇编语言中最基础和最重要的指令集之一,用于执行数学运算。让我们深入探讨各种算术指令的用法、工作原理和实际应用。
; ===================================================================
; 汇编语言算术指令完全指南
; 架构: x86/x86-64
; 示例使用NASM语法
; ===================================================================
1. 📋 目录
; ===================================================================
; 1. 📊 基本算术指令
; 1.1 ADD - 加法
; 1.2 SUB - 减法
; 1.3 INC - 递增
; 1.4 DEC - 递减
; 1.5 NEG - 取负
;
; 2. 🔢 乘法和除法
; 2.1 MUL - 无符号乘法
; 2.2 IMUL - 有符号乘法
; 2.3 DIV - 无符号除法
; 2.4 IDIV - 有符号除法
; 2.5 CBW/CWDE/CDQE - 符号扩展
; 2.6 CWD/CDQ/CQO - 符号扩展
;
; 3. 🎯 位运算指令
; 3.1 AND - 逻辑与
; 3.2 OR - 逻辑或
; 3.3 XOR - 逻辑异或
; 3.4 NOT - 逻辑非
; 3.5 TEST - 测试
;
; 4. 🔄 移位和循环指令
; 4.1 SHL/SHR - 逻辑移位
; 4.2 SAL/SAR - 算术移位
; 4.3 ROL/ROR - 循环移位
; 4.4 RCL/RCR - 带进位循环移位
;
; 5. 🏁 标志寄存器
; 5.1 状态标志
; 5.2 控制标志
; 5.3 条件跳转
;
; 6. 🧮 扩展运算
; 6.1 ADC - 带进位加法
; 6.2 SBB - 带借位减法
; 6.3 XADD - 交换并相加
; 6.4 CMPXCHG - 比较并交换
;
; 7. 📈 整数运算
; 7.1 扩展精度运算
; 7.2 BCD运算
; 7.3 十进制调整
;
; 8. 🔧 浮点运算
; 8.1 FPU基本指令
; 8.2 SSE浮点运算
; 8.3 AVX浮点运算
;
; 9. ⚡ 优化技巧
; 9.1 快速乘法技巧
; 9.2 除法优化
; 9.3 位运算技巧
;
; 10. 🎪 实际应用
; 10.1 数学函数实现
; 10.2 加密算法
; 10.3 图形计算
; ===================================================================
1. 📊 基本算术指令
1.1 ADD - 加法指令
section .data
num1 dd 100
num2 dd 50
result dd 0
section .text
global _start
_start:
; ============================================
; ADD 指令 - 加法
; 语法: ADD 目标操作数, 源操作数
; 功能: 目标操作数 = 目标操作数 + 源操作数
; 影响标志: OF, SF, ZF, AF, CF, PF
; ============================================
; 1.1 寄存器相加
mov eax, 10
mov ebx, 20
add eax, ebx ; eax = 10 + 20 = 30
; 1.2 寄存器与立即数相加
add eax, 5 ; eax = 30 + 5 = 35
; 1.3 内存与寄存器相加
mov dword [result], 100
add dword [result], eax ; [result] = 100 + 35 = 135
; 1.4 内存与立即数相加
add dword [num1], 25 ; [num1] = 100 + 25 = 125
; 1.5 不同大小的操作数
mov al, 200 ; 8位
add al, 100 ; 进位到CF
mov bx, 30000 ; 16位
add bx, 40000 ; 可能产生进位
mov ecx, 0xFFFFFFFF ; 32位
add ecx, 1 ; 产生进位,ecx = 0
; 1.6 多个数相加
mov eax, 10
add eax, 20 ; eax = 30
add eax, 30 ; eax = 60
add eax, 40 ; eax = 100
; 1.7 使用数组
section .data
array dd 1, 2, 3, 4, 5
array_len equ ($ - array) / 4
section .text
mov esi, array
mov ecx, array_len
xor eax, eax ; 清零eax,用于求和
sum_loop:
add eax, [esi] ; 累加数组元素
add esi, 4 ; 移动到下一个元素
loop sum_loop ; ecx--,如果ecx != 0则跳转
; 此时 eax = 1+2+3+4+5 = 15
; 1.8 检测溢出
mov al, 100
add al, 28 ; 结果128 > 127(有符号8位最大值)
; 设置OF(溢出标志)和SF(符号标志)
; 检查是否溢出
jo overflow_detected
jmp no_overflow
overflow_detected:
; 处理溢出
; ...
no_overflow:
; 1.9 加法与标志位
mov eax, 0x7FFFFFFF ; 最大正有符号32位整数
add eax, 1 ; 溢出到负数
; SF=1(负号), OF=1(溢出), ZF=0(非零)
; 1.10 清空寄存器技巧
xor eax, eax ; 比 mov eax, 0 更高效
add eax, 10 ; eax = 10
; 1.11 自增技巧
add eax, 1 ; 递增1
; 可以使用 inc eax,但 inc 不影响CF标志
; 1.12 大数加法(64位)
; 低32位
mov eax, 0xFFFFFFFF
mov ebx, 1
add eax, ebx ; eax = 0, CF=1
; 高32位(带进位)
mov edx, 0
adc edx, 0 ; edx = 1(如果有进位)
; 结果:edx:eax = 0x1:0x0 = 0x100000000
; 1.13 字符串数字相加
section .data
str_num1 db "12345", 0
str_num2 db "67890", 0
result_str db 10 dup(0) ; 10字节缓冲区
section .text
; 转换字符串为数字并相加
call atoi
; 这里简化,实际需要转换函数
; 退出程序
mov eax, 1 ; sys_exit
xor ebx, ebx ; 返回0
int 0x80
atoi:
; 字符串转整数函数
; ...
ret
1.2 SUB - 减法指令
section .text
global _start
_start:
; ============================================
; SUB 指令 - 减法
; 语法: SUB 目标操作数, 源操作数
; 功能: 目标操作数 = 目标操作数 - 源操作数
; 影响标志: OF, SF, ZF, AF, CF, PF
; ============================================
; 2.1 基本减法
mov eax, 100
mov ebx, 30
sub eax, ebx ; eax = 100 - 30 = 70
; 2.2 立即数减法
sub eax, 20 ; eax = 70 - 20 = 50
; 2.3 内存减法
mov dword [result], 200
sub dword [result], 50 ; [result] = 200 - 50 = 150
; 2.4 求相反数
mov eax, 100
neg eax ; eax = -100
add eax, 150 ; eax = 50
; 2.5 标志位检查
mov al, 10
sub al, 20 ; al = -10(有符号),246(无符号)
; CF=1(借位), SF=1(负号), OF=0(无溢出)
; 2.6 比较大小
mov eax, 50
mov ebx, 100
sub eax, ebx ; 比较eax和ebx
jl less_than ; 如果eax < ebx则跳转
jmp not_less
less_than:
; eax < ebx的情况
; ...
not_less:
; 2.7 清空寄存器
sub eax, eax ; eax = 0
; 比 mov eax, 0 更高效,但会设置标志位
; 2.8 减法溢出检测
mov al, -128 ; 有符号8位最小值
sub al, 1 ; 溢出到127
; OF=1(溢出), SF=0(正号)
jo subtraction_overflow
subtraction_overflow:
; 处理减法溢出
; ...
; 2.9 大数减法(64位)
; 低32位
mov eax, 0
mov ebx, 1
sub eax, ebx ; eax = 0xFFFFFFFF, CF=1(借位)
; 高32位(带借位)
mov edx, 0
sbb edx, 0 ; edx = 0xFFFFFFFF(有借位)
; 结果:edx:eax = 0xFFFFFFFF:0xFFFFFFFF = -1
; 2.10 数组元素相减
section .data
numbers dd 100, 200, 300, 400, 500
diff dd 0
section .text
mov esi, numbers
mov eax, [esi+4] ; 第二个元素
sub eax, [esi] ; 减去第一个元素
mov [diff], eax ; diff = 200 - 100 = 100
; 2.11 递减计数
mov ecx, 10
countdown:
; 循环体
; ...
sub ecx, 1 ; ecx--
jnz countdown ; 如果ecx != 0则继续
; 2.12 求绝对值
mov eax, -100
cmp eax, 0
jge positive
neg eax ; 如果是负数,取反
positive:
; 此时eax包含绝对值
; 2.13 计算偏移量
mov eax, buffer_end
mov ebx, buffer_start
sub eax, ebx ; eax = 缓冲区大小
; 2.14 减法与加法结合
mov eax, 100
sub eax, 30 ; eax = 70
add eax, 20 ; eax = 90
sub eax, 10 ; eax = 80
; 2.15 使用LEA进行算术
lea eax, [ebx + ecx*4 - 10] ; eax = ebx + ecx*4 - 10
; 比多个add/sub更快
; 退出程序
mov eax, 1
xor ebx, ebx
int 0x80
1.3 INC/DEC - 递增/递减指令
section .data
counter dd 0
index dd 0
section .text
global _start
_start:
; ============================================
; INC 指令 - 递增
; 语法: INC 目标操作数
; 功能: 目标操作数 = 目标操作数 + 1
; 影响标志: OF, SF, ZF, AF, PF
; 注意: INC 不影响 CF 标志!
; ============================================
; 3.1 INC 基本用法
mov eax, 10
inc eax ; eax = 11
inc byte [counter] ; 8位内存递增
inc word [counter] ; 16位内存递增
inc dword [counter] ; 32位内存递增
; 3.2 循环计数器
mov ecx, 10
loop_start:
; 循环体
inc byte [index] ; 索引递增
loop loop_start ; ecx--, 如果ecx!=0则跳转
; 3.3 指针递增
mov esi, buffer
mov ecx, 100
copy_loop:
mov al, [esi]
; 处理数据...
inc esi ; 移动到下一个字节
loop copy_loop
; 3.4 数组遍历
mov esi, array
mov edi, dest_array
mov ecx, array_size
array_copy:
mov eax, [esi]
mov [edi], eax
add esi, 4 ; 32位数组,加4字节
add edi, 4
loop array_copy
; ============================================
; DEC 指令 - 递减
; 语法: DEC 目标操作数
; 功能: 目标操作数 = 目标操作数 - 1
; 影响标志: OF, SF, ZF, AF, PF
; 注意: DEC 不影响 CF 标志!
; ============================================
; 3.5 DEC 基本用法
mov ebx, 20
dec ebx ; ebx = 19
dec byte [counter] ; 8位内存递减
dec word [counter] ; 16位内存递减
dec dword [counter] ; 32位内存递减
; 3.6 递减循环
mov ecx, 10
dec ecx ; ecx = 9
jnz not_zero ; 如果ecx != 0则跳转
; 3.7 倒计数
mov ecx, 10
countdown_loop:
; 循环体,从10到1
; ...
dec ecx
jnz countdown_loop
; 3.8 指针递减
mov edi, buffer_end
mov ecx, 100
reverse_copy:
dec edi ; 移动到前一个字节
mov al, [edi]
; 处理数据...
loop reverse_copy
; 3.9 使用INC/DEC避免影响CF标志
mov eax, 0xFFFFFFFF
stc ; 设置CF=1
inc eax ; eax = 0, CF保持不变(仍为1)
; 对比ADD会改变CF
mov eax, 0xFFFFFFFF
stc ; 设置CF=1
add eax, 1 ; eax = 0, CF=1(有进位)
; 3.10 循环展开中的INC/DEC
mov ecx, 100
mov esi, source
mov edi, destination
unrolled_loop:
; 每次迭代处理4个元素
mov eax, [esi]
mov [edi], eax
add esi, 4
add edi, 4
mov eax, [esi]
mov [edi], eax
add esi, 4
add edi, 4
mov eax, [esi]
mov [edi], eax
add esi, 4
add edi, 4
mov eax, [esi]
mov [edi], eax
add esi, 4
add edi, 4
sub ecx, 4 ; 处理了4个元素
jnz unrolled_loop
; 3.11 边界检查
mov ecx, array_size
jecxz empty_array ; 如果ecx=0则跳转
process_array:
dec ecx
js done ; 如果ecx变为负数则完成
; 处理array[ecx]
mov eax, [array + ecx*4]
; ...
jmp process_array
empty_array:
; 数组为空的情况
; ...
done:
; 3.12 多精度递增
; 递增64位值
add dword [low_dword], 1
adc dword [high_dword], 0
; 使用INC(不影响CF)
inc dword [low_dword]
jnz no_carry
inc dword [high_dword]
no_carry:
; 3.13 性能考虑
; INC/DEC 在大多数现代CPU上与ADD/SUB同样快
; 但INC/DEC不影响CF,有时很有用
; 退出程序
mov eax, 1
xor ebx, ebx
int 0x80
section .bss
buffer resb 100
dest_array resd 100
source resd 100
destination resd 100
array resd 100
array_size equ 100
low_dword resd 1
high_dword resd 1
2. 🔢 乘法和除法
2.1 MUL/IMUL - 乘法指令
section .data
; 测试数据
byte1 db 10
byte2 db 20
word1 dw 1000
word2 dw 2000
dword1 dd 100000
dword2 dd 200000
result8 dw 0 ; 8位乘法结果(16位)
result16 dd 0 ; 16位乘法结果(32位)
result32 dq 0 ; 32位乘法结果(64位)
section .text
global _start
_start:
; ============================================
; MUL 指令 - 无符号乘法
; 语法: MUL 源操作数
; 8位: AL * src8 → AX
; 16位: AX * src16 → DX:AX
; 32位: EAX * src32 → EDX:EAX
; 64位: RAX * src64 → RDX:RAX
; 影响标志: OF, CF(如果结果的高半部分为0则清除)
; ============================================
; 4.1 8位无符号乘法
mov al, 10 ; AL = 10
mov bl, 20 ; BL = 20
mul bl ; AX = AL * BL = 200
mov [result8], ax ; 保存结果
; 4.2 16位无符号乘法
mov ax, 1000 ; AX = 1000
mov bx, 2000 ; BX = 2000
mul bx ; DX:AX = AX * BX = 2,000,000
; DX = 高位字,AX = 低位字
mov [result16], ax
mov [result16+2], dx
; 4.3 32位无符号乘法
mov eax, 100000 ; EAX = 100,000
mov ebx, 200000 ; EBX = 200,000
mul ebx ; EDX:EAX = EAX * EBX = 20,000,000,000
mov [result32], eax
mov [result32+4], edx
; 4.4 大数乘法示例
; 计算 1234 * 5678
mov ax, 1234
mov bx, 5678
mul bx ; DX:AX = 1234 * 5678 = 7,006,652
; 4.5 检查溢出
mov al, 100
mov bl, 3
mul bl ; AX = 300, CF=OF=0(无溢出)
mov al, 200
mov bl, 2
mul bl ; AX = 400, CF=OF=1(溢出,AH != 0)
; 4.6 内存操作数
mov al, [byte1]
mul byte [byte2] ; AL * [byte2] → AX
mov ax, [word1]
mul word [word2] ; AX * [word2] → DX:AX
; ============================================
; IMUL 指令 - 有符号乘法
; 语法1: IMUL 源操作数(与MUL相同)
; 语法2: IMUL 目标, 源
; 语法3: IMUL 目标, 源, 立即数
; 影响标志: OF, CF(如果结果符合目标则清除)
; ============================================
; 4.7 单操作数形式(与MUL相同)
mov al, -10 ; AL = -10(有符号)
mov bl, 20 ; BL = 20
imul bl ; AX = -200
; 结果在AX中
; 4.8 双操作数形式
mov eax, 100
mov ebx, -3
imul eax, ebx ; EAX = EAX * EBX = -300
imul eax, 5 ; EAX = EAX * 5 = -1500
; 4.9 三操作数形式
imul eax, ebx, 10 ; EAX = EBX * 10
; 4.10 有符号乘法示例
; 计算 (-123) * 456
mov eax, -123
mov ebx, 456
imul ebx ; EDX:EAX = -123 * 456 = -56,088
; 4.11 检查有符号溢出
mov al, 100
mov bl, 2
imul bl ; AX = 200, OF=0(无溢出)
mov al, 100
mov bl, 3
imul bl ; AX = 300, OF=1(溢出)
; 4.12 使用IMUL进行快速乘法
; 乘以常数(使用移位和加法)
mov eax, 123
imul eax, 9 ; EAX = 123 * 9
; 编译为: eax * 8 + eax = 984 + 123 = 1107
; 乘以5: eax * 4 + eax
; 乘以10: eax * 8 + eax * 2
; 4.13 扩展精度乘法
; 计算64位 * 64位 → 128位
; 假设我们要计算 a*b,其中a和b是64位数
; a存储在 EDX:EAX, b存储在 ECX:EBX
; 结果存储在 内存中
section .data
a_high dd 0x00000001
a_low dd 0x23456789
b_high dd 0x00000001
b_low dd 0xABCDEF01
section .text
; 加载a
mov eax, [a_low]
mov edx, [a_high]
; 加载b
mov ebx, [b_low]
mov ecx, [b_high]
; 计算 a_low * b_low
mul ebx ; EDX:EAX = EAX * EBX
; 保存低64位结果
mov [result64_low], eax
mov [result64_low+4], edx
; 计算 a_high * b_low
mov eax, [a_high]
mul ebx ; EDX:EAX = a_high * b_low
; 计算 a_low * b_high
mov ebx, [b_high]
mov ecx, eax ; 保存中间结果
mov eax, [a_low]
mul ebx ; EDX:EAX = a_low * b_high
; 相加得到高64位
add eax, [result64_low+4] ; 加上之前的进位
adc edx, 0
add eax, ecx ; 加上a_high*b_low的结果
adc edx, 0
; 保存高64位结果
mov [result64_high], eax
mov [result64_high+4], edx
; 4.14 乘法表生成
mov ecx, 10 ; 行数
mov ebx, 1 ; 当前行
multiplication_table:
push ecx
mov ecx, 10 ; 列数
mov eax, 1 ; 当前列
inner_loop:
; 计算 eax * ebx
imul eax, ebx
; 这里可以输出结果...
inc eax
loop inner_loop
pop ecx
inc ebx
loop multiplication_table
; 4.15 矩阵乘法示例
; 计算 C = A * B
; 其中A是m×n矩阵,B是n×p矩阵
section .data
; 简单示例: 2x2矩阵
matrix_a dd 1, 2, 3, 4 ; 2x2矩阵
matrix_b dd 5, 6, 7, 8 ; 2x2矩阵
matrix_c dd 0, 0, 0, 0 ; 结果矩阵
section .text
; 计算矩阵乘法
; C[0,0] = A[0,0]*B[0,0] + A[0,1]*B[1,0]
mov eax, [matrix_a] ; A[0,0]
imul eax, [matrix_b] ; * B[0,0]
mov ebx, eax
mov eax, [matrix_a+4] ; A[0,1]
imul eax, [matrix_b+8] ; * B[1,0]
add ebx, eax
mov [matrix_c], ebx ; C[0,0]
; 类似计算其他元素...
; 4.16 性能优化技巧
; 使用LEA进行快速乘以小常数
mov eax, 123
lea eax, [eax + eax*2] ; eax = eax * 3
lea eax, [eax*4] ; eax = eax * 4
lea eax, [eax + eax*4] ; eax = eax * 5
; 乘以常数9: eax * 8 + eax
mov ebx, eax
shl eax, 3 ; eax * 8
add eax, ebx ; + eax
; 退出程序
mov eax, 1
xor ebx, ebx
int 0x80
section .bss
result64_low resd 2
result64_high resd 2
2.2 DIV/IDIV - 除法指令
section .data
; 测试数据
dividend32 dd 100
divisor32 dd 7
quotient32 dd 0
remainder32 dd 0
dividend64 dq 1000
divisor64 dd 7
quotient64 dd 0
remainder64 dd 0
dividend_neg dd -100
divisor_neg dd 7
; 用于扩展精度除法的数据
dividend128 dq 0x12345678, 0x9ABCDEF0 ; 128位被除数
divisor64_single dd 0x1000 ; 32位除数
section .text
global _start
_start:
; ============================================
; DIV 指令 - 无符号除法
; 语法: DIV 除数
; 8位: AX / src8 → AL=商, AH=余数
; 16位: DX:AX / src16 → AX=商, DX=余数
; 32位: EDX:EAX / src32 → EAX=商, EDX=余数
; 64位: RDX:RAX / src64 → RAX=商, RDX=余数
; 注意: 如果商溢出(>目标寄存器容量)会触发除法错误
; ============================================
; 5.1 8位无符号除法
mov ax, 100 ; AX = 100
mov bl, 7 ; BL = 7
div bl ; AL = 14, AH = 2
; 商: AL = 100/7 = 14
; 余数: AH = 100%7 = 2
; 5.2 16位无符号除法
mov dx, 0 ; 高16位清零
mov ax, 1000 ; 低16位
mov bx, 7
div bx ; AX = 142, DX = 6
; 5.3 32位无符号除法
mov edx, 0 ; 高32位清零
mov eax, 100 ; 低32位
mov ebx, 7
div ebx ; EAX = 14, EDX = 2
mov [quotient32], eax
mov [remainder32], edx
; 5.4 64位无符号除法(32位模式下)
; 被除数在EDX:EAX,除数是32位
mov edx, 0x00000001 ; 高32位 = 1
mov eax, 0x00000000 ; 低32位 = 0
; 总共: 0x100000000 = 4294967296
mov ebx, 1000000000 ; 除数 = 1,000,000,000
div ebx ; EAX = 4, EDX = 294967296
; 5.5 检查除法错误
mov ax, 1000
mov bl, 0 ; 除数为零!
; div bl ; 这会触发除法错误(中断0)
; 需要先检查除数
test bl, bl
jz division_error
; 5.6 处理大被除数
; 被除数超过16位
mov ax, 0xFFFF ; AX = 65535
add ax, 1 ; AX = 0, CF=1
; 需要处理进位
jc handle_carry
; ============================================
; IDIV 指令 - 有符号除法
; 语法: IDIV 除数
; 格式与DIV相同,但处理有符号数
; 余数的符号与被除数相同
; ============================================
; 5.7 8位有符号除法
mov ax, -100 ; AX = -100
cwd ; 扩展AX到DX:AX
mov bx, 7
idiv bx ; AX = -14, DX = -2
; 5.8 32位有符号除法
mov eax, -100
cdq ; 扩展EAX到EDX:EAX
mov ebx, 7
idiv ebx ; EAX = -14, EDX = -2
; 5.9 有符号除法示例
mov eax, 100
mov ebx, -7
cdq ; 扩展EAX到EDX:EAX
idiv ebx ; EAX = -14, EDX = 2
; 5.10 符号扩展指令
; CBW: 扩展AL到AX
; CWD: 扩展AX到DX:AX
; CWDE: 扩展AX到EAX
; CDQ: 扩展EAX到EDX:EAX
mov al, -5
cbw ; AX = 0xFFFB (-5)
mov ax, -1000
cwd ; DX:AX = 0xFFFF:0xFC18 (-1000)
mov eax, -100000
cdq ; EDX:EAX = 0xFFFFFFFF:0xFFFE7960 (-100000)
; 5.11 扩展精度除法
; 128位 ÷ 64位 = 64位商,64位余数
; 在32位模式下模拟
; 被除数: EDX:ECX:EBX:EAX (128位)
; 除数: 内存中的64位数
; 5.12 除法优化技巧
; 除以常数2的幂可以使用移位
mov eax, 100
shr eax, 1 ; eax = 50 (除以2)
; 除以非2的幂常数
; 编译器会使用魔术数乘法优化
; 5.13 计算模运算
mov eax, 100
mov ebx, 7
xor edx, edx ; 清零EDX
div ebx ; EAX=商, EDX=余数
; EDX包含 100 mod 7 = 2
; 5.14 同时获取商和余数
mov eax, 12345
mov ebx, 100
xor edx, edx
div ebx
; EAX = 123 (商)
; EDX = 45 (余数)
; 5.15 浮点转整数除法
; 计算 eax = (eax * 100) / divisor
mov ebx, 100
imul eax, ebx ; eax = eax * 100
cdq ; 扩展到EDX:EAX
idiv dword [divisor32] ; 除以除数
; 5.16 检查除法溢出
; 对于有符号除法,最大负数除以-1会溢出
mov eax, 0x80000000 ; 最小有符号32位数
mov ebx, -1
cdq
idiv ebx ; 会溢出!
; 安全检查
cmp eax, 0x80000000
jne safe_divide
cmp ebx, -1
jne safe_divide
; 处理溢出情况
safe_divide:
; 正常除法
; 5.17 使用除法计算平均值
mov eax, 100
add eax, 200
add eax, 300 ; 总和 = 600
mov ebx, 3
xor edx, edx
div ebx ; 平均值 = 200
; 5.18 百分比计算
; 计算 (value * 100) / total
mov eax, 75 ; 值
mov ebx, 100 ; 百分比基数
imul eax, ebx ; eax = 7500
mov ebx, 150 ; 总量
xor edx, edx
div ebx ; 百分比 = 50
; 5.19 大数除法示例
; 实现128位 ÷ 64位除法
section .bss
dividend_hi resd 2
dividend_lo resd 2
divisor_64 resd 2
quotient_64 resd 2
remainder_64 resd 2
section .text
; 伪代码实现
; 这需要多次移位和减法操作
; 实际实现较复杂,这里展示概念
; 5.20 除法错误处理
jmp division_end
division_error:
; 处理除数为零的情况
mov eax, 0xFFFFFFFF ; 返回错误值
mov edx, 0xFFFFFFFF
; 或者跳转到错误处理程序
handle_carry:
; 处理进位的大数除法
; ...
; 5.21 使用AAM指令(ASCII调整)
; 用于BCD除法后调整
mov ax, 0105h ; AX = 105 (BCD)
aam ; AH = 1, AL = 5
division_end:
; 退出程序
mov eax, 1
xor ebx, ebx
int 0x80
3. 🎯 位运算指令
3.1 逻辑位运算
section .data
; 测试数据
test_byte db 0b10101010
test_dword dd 0x12345678
mask dd 0x0000FFFF
flags dd 0
; 位掩码常量
FLAG_A equ 0x00000001
FLAG_B equ 0x00000002
FLAG_C equ 0x00000004
FLAG_D equ 0x00000008
FLAG_ALL equ FLAG_A | FLAG_B | FLAG_C | FLAG_D
section .text
global _start
_start:
; ============================================
; AND 指令 - 逻辑与
; 语法: AND 目标, 源
; 功能: 目标 = 目标 & 源
; 影响标志: OF=0, CF=0, SF, ZF, PF
; ============================================
; 6.1 AND 基本用法
mov eax, 0b11001100
mov ebx, 0b10101010
and eax, ebx ; EAX = 0b10001000
; 6.2 清零特定位
mov eax, 0xFF
and eax, 0xF0 ; 清零低4位: EAX = 0xF0
; 6.3 检查奇偶性
mov eax, 123
test eax, 1 ; 检查最低位
jnz odd_number ; 如果ZF=0(位1),则是奇数
; 6.4 提取特定位
mov eax, 0x12345678
and eax, 0x0000FFFF ; 提取低16位: EAX = 0x5678
; 6.5 掩码操作
mov eax, [flags]
and eax, FLAG_A ; 检查FLAG_A是否设置
jnz flag_a_set
; ============================================
; OR 指令 - 逻辑或
; 语法: OR 目标, 源
; 功能: 目标 = 目标 | 源
; 影响标志: OF=0, CF=0, SF, ZF, PF
; ============================================
; 6.6 OR 基本用法
mov eax, 0b11001100
mov ebx, 0b00110011
or eax, ebx ; EAX = 0b11111111
; 6.7 设置特定位
mov eax, [flags]
or eax, FLAG_A ; 设置FLAG_A
or eax, FLAG_B ; 设置FLAG_B
mov [flags], eax
; 6.8 合并位域
mov eax, 0x1200
mov ebx, 0x0034
or eax, ebx ; EAX = 0x1234
; ============================================
; XOR 指令 - 逻辑异或
; 语法: XOR 目标, 源
; 功能: 目标 = 目标 ^ 源
; 影响标志: OF=0, CF=0, SF, ZF, PF
; ============================================
; 6.9 XOR 基本用法
mov eax, 0b11001100
mov ebx, 0b10101010
xor eax, ebx ; EAX = 0b01100110
; 6.10 清零寄存器
xor eax, eax ; EAX = 0,比mov eax, 0更快
; 6.11 切换位状态
mov eax, [flags]
xor eax, FLAG_A ; 切换FLAG_A状态
mov [flags], eax
; 6.12 交换值(不使用临时变量)
mov eax, 10
mov ebx, 20
xor eax, ebx ; EAX = 10 ^ 20
xor ebx, eax ; EBX = 20 ^ (10 ^ 20) = 10
xor eax, ebx ; EAX = (10 ^ 20) ^ 10 = 20
; 6.13 简单加密/解密
mov eax, 0x12345678
mov ebx, 0x9ABCDEF0 ; 密钥
xor eax, ebx ; 加密
xor eax, ebx ; 再次XOR解密
; ============================================
; NOT 指令 - 逻辑非
; 语法: NOT 目标
; 功能: 目标 = ~目标
; 不影响标志位!
; ============================================
; 6.14 NOT 基本用法
mov eax, 0b11001100
not eax ; EAX = 0b00110011
; 6.15 求补码(负值)
mov eax, 42
not eax
inc eax ; EAX = -42
; 6.16 位反转
mov eax, 0x0000FFFF
not eax ; EAX = 0xFFFF0000
; ============================================
; TEST 指令 - 测试
; 语法: TEST 目标, 源
; 功能: 目标 & 源,只设置标志位
; 影响标志: OF=0, CF=0, SF, ZF, PF
; ============================================
; 6.17 TEST 基本用法
mov eax, 0b00001000
test eax, 0b00001000
jnz bit_set ; 如果位3设置则跳转
; 6.18 测试多个位
test eax, FLAG_A | FLAG_B
jnz either_flag_set
; 6.19 测试零值
test eax, eax
jz is_zero
; 6.20 检查符号
test eax, 0x80000000
jnz is_negative
; 6.21 位操作应用示例
; 示例1: 设置位掩码
mov eax, 0
bts eax, 3 ; 设置位3(如果可用)
or eax, 1 << 3 ; 设置位3的替代方法
; 示例2: 清除位掩码
and eax, ~(1 << 3) ; 清除位3
; 示例3: 切换位掩码
xor eax, 1 << 3 ; 切换位3
; 示例4: 检查位掩码
test eax, 1 << 3
jnz bit_3_set
; 示例5: 提取位域
mov eax, 0x12345678
and eax, 0x0000FF00 ; 提取字节1
shr eax, 8 ; 右移8位
; 示例6: 插入位域
mov eax, 0x12345678
and eax, 0xFFFF00FF ; 清除字节1
mov ebx, 0x99
shl ebx, 8
or eax, ebx ; 设置字节1为0x99
; 示例7: 位计数(popcount)
mov eax, 0b10101010
xor ecx, ecx ; 计数器清零
count_bits:
test eax, eax
jz count_done
shr eax, 1
adc ecx, 0 ; 如果CF=1则加1
jmp count_bits
count_done:
; ECX包含位数
; 示例8: 查找最低有效位1
mov eax, 0b00010100
bsf ecx, eax ; ECX = 2(位2是第一个1)
; 如果没有BSF指令:
mov ebx, eax
dec ebx
not eax
and eax, ebx ; 清除最低有效位1
; 示例9: 交换字节序
mov eax, 0x12345678
bswap eax ; EAX = 0x78563412
; 示例10: 位反转(没有专用指令时)
mov eax, 0b11001100
mov ecx, 32 ; 32位反转
reverse_bits:
rcr eax, 1 ; 右移,最低位到CF
rcl ebx, 1 ; 左移,CF到最低位
loop reverse_bits
; 6.22 标志位操作
; 保存和恢复标志位
pushf ; 保存标志寄存器
; ... 修改标志位 ...
popf ; 恢复标志寄存器
; 设置/清除特定标志
clc ; 清除CF
stc ; 设置CF
cmc ; 取反CF
cli ; 清除IF(中断标志)
sti ; 设置IF
cld ; 清除DF(方向标志)
std ; 设置DF
; 6.23 条件码操作
; 根据标志设置字节
mov al, 0
setc al ; 如果CF=1则AL=1
setz al ; 如果ZF=1则AL=1
sets al ; 如果SF=1则AL=1
seto al ; 如果OF=1则AL=1
; 6.24 位域操作
; 提取位5-8
mov eax, 0x12345678
shr eax, 5
and eax, 0xF ; 位5-8
; 插入位5-8
mov ebx, 0x9
shl ebx, 5
and eax, ~(0xF << 5) ; 清除位5-8
or eax, ebx ; 设置新值
; 6.25 位图操作
; 设置位图中的位
mov edi, bitmap
mov eax, 42 ; 位索引
mov ebx, eax
shr eax, 5 ; 计算字节偏移
and ebx, 0x1F ; 计算位偏移
bts [edi + eax*4], ebx ; 设置位
; 6.26 位运算优化技巧
; 乘以2的幂
mov eax, 10
shl eax, 1 ; 乘以2
shl eax, 2 ; 乘以4
shl eax, 3 ; 乘以8
; 除以2的幂
mov eax, 100
shr eax, 1 ; 除以2
sar eax, 1 ; 有符号除以2
; 检查是否是2的幂
mov eax, 64
dec eax
test eax, 64
jz is_power_of_two
; 6.27 位运算实际应用
; 应用1: 权限系统
%define PERM_READ 0x01
%define PERM_WRITE 0x02
%define PERM_EXEC 0x04
%define PERM_ALL PERM_READ | PERM_WRITE | PERM_EXEC
mov eax, PERM_READ | PERM_WRITE
test eax, PERM_READ
jnz has_read_perm
; 应用2: 选项处理
%define OPT_A 0x01
%define OPT_B 0x02
%define OPT_C 0x04
mov ebx, OPT_A | OPT_C
test ebx, OPT_A
jnz option_a_enabled
; 应用3: 错误码
%define ERR_NONE 0x00
%define ERR_IO 0x01
%define ERR_MEM 0x02
%define ERR_INVALID 0x04
mov ecx, ERR_IO | ERR_MEM
test ecx, ERR_IO
jnz io_error
; 退出程序
mov eax, 1
xor ebx, ebx
int 0x80
; 标签定义
odd_number:
flag_a_set:
either_flag_set:
is_zero:
is_negative:
bit_3_set:
is_power_of_two:
has_read_perm:
option_a_enabled:
io_error:
; 错误处理代码
; ...
section .bss
bitmap resd 256 ; 256个双字 = 8192位
4. 🔄 移位和循环指令
4.1 移位指令
section .data
test_value dd 0x12345678
shift_count db 4
; 测试模式
bit_pattern dd 0b10101010101010101010101010101010
signed_val dd -100
unsigned_val dd 100
section .text
global _start
_start:
; ============================================
; 移位指令
; 语法: SHL/SHR/SAL/SAR 目标, 计数
; 计数: 立即数或CL寄存器
; 影响标志: OF, SF, ZF, AF, PF, CF
; ============================================
; 7.1 SHL - 逻辑左移
; 向左移位,最低位补0,最高位移入CF
mov eax, 0b00010001
shl eax, 1 ; EAX = 0b00100010, CF = 0
; 7.2 SHR - 逻辑右移
; 向右移位,最高位补0,最低位移入CF
mov eax, 0b10001000
shr eax, 1 ; EAX = 0b01000100, CF = 0
; 7.3 SAL - 算术左移(与SHL相同)
; 向左移位,最低位补0,最高位移入CF
mov eax, 0b00010001
sal eax, 1 ; 同SHL
; 7.4 SAR - 算术右移
; 向右移位,最高位用符号位填充,最低位移入CF
mov eax, -8 ; 0xFFFFFFF8
sar eax, 1 ; EAX = -4 (0xFFFFFFFC), CF = 0
mov ebx, 8
sar ebx, 1 ; EBX = 4, CF = 0
; 7.5 使用CL作为移位计数
mov cl, 3
mov eax, 0x11111111
shl eax, cl ; EAX = 0x88888888
; 7.6 超过31的移位
mov cl, 33
mov eax, 0xFFFFFFFF
shr eax, cl ; 实际移位33 & 31 = 1位
; 7.7 移位应用:乘以2的幂
mov eax, 5
shl eax, 1 ; 乘以2: 10
shl eax, 2 ; 乘以4: 40
shl eax, 3 ; 乘以8: 320
; 7.8 移位应用:除以2的幂
mov eax, 100
shr eax, 1 ; 无符号除以2: 50
sar eax, 2 ; 有符号除以4: 12
; 7.9 移位应用:提取位域
mov eax, 0x12345678
; 提取位16-23
shr eax, 16
and eax, 0xFF ; EAX = 0x34
; 7.10 移位应用:组合位域
mov eax, 0x1200
mov ebx, 0x0034
shl eax, 8
or eax, ebx ; EAX = 0x1234
; 7.11 移位应用:位反转
mov eax, 0b11001100
mov ecx, 8
xor ebx, ebx
reverse_bits_loop:
shr eax, 1 ; 最低位到CF
rcl ebx, 1 ; CF到最高位
loop reverse_bits_loop
; 7.12 移位应用:乘法优化
; 乘以3: x*2 + x
mov eax, 10
mov ebx, eax
shl eax, 1 ; x*2
add eax, ebx ; +x
; 乘以5: x*4 + x
mov eax, 10
mov ebx, eax
shl eax, 2 ; x*4
add eax, ebx ; +x
; 乘以10: x*8 + x*2
mov eax, 10
mov ebx, eax
shl eax, 3 ; x*8
shl ebx, 1 ; x*2
add eax, ebx
; ============================================
; 循环移位指令
; 语法: ROL/ROR/RCL/RCR 目标, 计数
; 影响标志: OF, CF
; ============================================
; 7.13 ROL - 循环左移
; 向左循环移位,最高位移到CF和最低位
mov eax, 0b10001000
rol eax, 1 ; EAX = 0b00010001, CF = 1
; 7.14 ROR - 循环右移
; 向右循环移位,最低位移到CF和最高位
mov eax, 0b10001000
ror eax, 1 ; EAX = 0b01000100, CF = 0
; 7.15 RCL - 带进位循环左移
; 向左循环移位,通过CF
clc ; CF = 0
mov eax, 0b10001000
rcl eax, 1 ; EAX = 0b00010000, CF = 1
; 7.16 RCR - 带进位循环右移
; 向右循环移位,通过CF
stc ; CF = 1
mov eax, 0b10001000
rcr eax, 1 ; EAX = 0b11000100, CF = 0
; 7.17 循环移位应用:位旋转加密
mov eax, 0x12345678
mov cl, 4
rol eax, cl ; 左旋转4位
; 解密
ror eax, cl ; 右旋转4位
; 7.18 循环移位应用:检查位
mov eax, 0b00001000
mov ecx, 32
check_all_bits:
rcl eax, 1 ; 最高位到CF
jc bit_is_set
loop check_all_bits
; 7.19 移位标志位
; SHL/SAL: 如果符号改变,OF=1
; SHR: 如果移位前最高位是1,OF=1
; SAR: OF=0
; ROL/ROR: 如果符号改变,OF=1
; RCL/RCR: 复杂...
; 7.20 双精度移位
; SHLD - 双精度左移
; SHRD - 双精度右移
mov eax, 0x12345678
mov ebx, 0x9ABCDEF0
mov cl, 4
shld ebx, eax, cl ; EBX左移,从EAX移入位
shrd eax, ebx, cl ; EAX右移,从EBX移入位
; 7.21 移位与条件
; 检查第n位
mov eax, 0x12345678
bt eax, 3 ; 检查位3,结果在CF
jc bit_3_set_2
; 设置第n位
bts eax, 3 ; 设置位3
; 清除第n位
btr eax, 3 ; 清除位3
; 切换第n位
btc eax, 3 ; 切换位3
; 7.22 位扫描
; BSF - 向前位扫描
; BSR - 向后位扫描
mov eax, 0b00001000
bsf ecx, eax ; ECX = 3(最低设置位)
bsr edx, eax ; EDX = 3(最高设置位)
; 7.23 移位应用:浮点数操作
; 提取浮点数指数
mov eax, 0x40A00000 ; 5.0的浮点表示
shr eax, 23
and eax, 0xFF ; 指数
; 7.24 移位应用:BCD转换
; 二进制转BCD
mov eax, 123
mov ecx, 0
mov ebx, 10
bin_to_bcd:
xor edx, edx
div ebx ; EDX=余数, EAX=商
shl edx, cl
or ecx, edx
add cl, 4
test eax, eax
jnz bin_to_bcd
; 7.25 移位应用:CRC计算
mov eax, 0xFFFFFFFF ; CRC初始值
mov ecx, 32
mov edx, 0xEDB88320 ; CRC32多项式
crc_loop:
shr eax, 1
jnc no_xor
xor eax, edx
no_xor:
loop crc_loop
; 7.26 移位应用:乘法(不使用MUL)
; 俄罗斯农民乘法算法
mov eax, 13 ; 被乘数
mov ebx, 9 ; 乘数
xor ecx, ecx ; 结果
russian_peasant:
test ebx, 1
jz skip_add
add ecx, eax
skip_add:
shl eax, 1 ; 被乘数翻倍
shr ebx, 1 ; 乘数减半
jnz russian_peasant
; 结果在ECX中
; 7.27 移位应用:除法(不使用DIV)
; 恢复除法算法
mov eax, 100 ; 被除数
mov ebx, 7 ; 除数
xor edx, edx ; 余数
mov ecx, 32 ; 循环计数
restoring_division:
shl eax, 1 ; 左移被除数
rcl edx, 1 ; 带进位左移余数
; 尝试减法
sub edx, ebx
jnc subtraction_ok
add edx, ebx ; 恢复
clc
jmp next_bit
subtraction_ok:
stc
next_bit:
rcl eax, 1 ; 商位
loop restoring_division
; 商在EAX,余数在EDX
; 7.28 移位应用:位图操作
; 设置位图中的特定位
mov edi, bitmap
mov eax, 42 ; 位索引
mov ebx, eax
shr eax, 5 ; 计算双字索引
and ebx, 0x1F ; 计算位偏移
bts [edi + eax*4], ebx ; 设置位
; 7.29 移位应用:内存对齐
; 对齐到16字节边界
mov eax, 0x1234567F
add eax, 0x0F
and eax, 0xFFFFFFF0
; 7.30 移位应用:颜色操作
; 提取RGB分量
mov eax, 0x00FF00FF ; ARGB颜色
mov ebx, eax
and eax, 0x00FF0000
shr eax, 16 ; 红色分量
mov ecx, ebx
and ecx, 0x0000FF00
shr ecx, 8 ; 绿色分量
and ebx, 0x000000FF ; 蓝色分量
; 合并RGB分量
shl eax, 16
shl ecx, 8
or eax, ecx
or eax, ebx ; 合并后的颜色
; 7.31 移位应用:浮点技巧
; 快速绝对值
mov eax, -100
cdq
xor eax, edx
sub eax, edx ; EAX = |EAX|
; 快速最小值
mov eax, 10
mov ebx, 20
sub eax, ebx
sar eax, 31 ; 符号扩展
and eax, ebx
add eax, 10 ; EAX = min(10, 20)
; 退出程序
mov eax, 1
xor ebx, ebx
int 0x80
bit_3_set_2:
; 处理代码
; ...
section .bss
bitmap2 resd 256
5. 🏁 标志寄存器操作
section .data
; 测试数据
test_num1 dd 100
test_num2 dd 200
result_flags dd 0
; 条件跳转测试
compare_a dd 10
compare_b dd 20
; 标志测试
signed_a dd -10
signed_b dd 20
unsigned_a dd 0xFFFFFFF0 ; 4294967280
unsigned_b dd 10
section .text
global _start
_start:
; ============================================
; 标志寄存器 (EFLAGS) 重要位
; CF - 进位标志 (bit 0)
; PF - 奇偶标志 (bit 2)
; AF - 辅助进位标志 (bit 4)
; ZF - 零标志 (bit 6)
; SF - 符号标志 (bit 7)
; TF - 陷阱标志 (bit 8)
; IF - 中断允许标志 (bit 9)
; DF - 方向标志 (bit 10)
; OF - 溢出标志 (bit 11)
; ============================================
; 8.1 直接操作标志寄存器
pushf ; 将EFLAGS压栈
pop eax ; 弹出到EAX
mov [result_flags], eax
; 设置标志
push dword [result_flags]
popf ; 从堆栈设置EFLAGS
; 8.2 进位标志 (CF) 操作
clc ; 清除CF
stc ; 设置CF
cmc ; 取反CF
; 使用ADC(带进位加法)
mov eax, 0xFFFFFFFF
mov ebx, 1
add eax, ebx ; EAX=0, CF=1
adc edx, 0 ; EDX += CF
; 8.3 方向标志 (DF) 操作
cld ; 清除DF(向前移动)
std ; 设置DF(向后移动)
; 影响字符串操作
cld
mov esi, source
mov edi, destination
mov ecx, 100
rep movsb ; 从ESI复制到EDI,向前移动
; 8.4 测试CF标志
mov al, 0xFF
add al, 1 ; AL=0, CF=1
jc carry_occurred
mov al, 0x7F
add al, 1 ; AL=0x80, CF=0, OF=1
jo overflow_occurred
; 8.5 符号标志 (SF)
mov eax, -10
add eax, 5 ; EAX=-5, SF=1
js negative_result
mov eax, 10
sub eax, 5 ; EAX=5, SF=0
jns positive_result
; 8.6 零标志 (ZF)
mov eax, 10
sub eax, 10 ; EAX=0, ZF=1
jz is_zero
test eax, eax ; 测试是否为0
jz is_zero_2
cmp eax, 0 ; 比较是否为0
je is_zero_3
; 8.7 溢出标志 (OF)
; 有符号溢出检测
mov al, 0x7F ; 127
add al, 1 ; AL=0x80 (-128), OF=1
jo signed_overflow
mov al, 0x80 ; -128
sub al, 1 ; AL=0x7F (127), OF=1
jo signed_overflow_2
; 8.8 奇偶标志 (PF)
mov al, 0b00100111 ; 有偶数个1
add al, 0 ; PF=1
jp even_parity
mov al, 0b00100110 ; 有奇数个1
add al, 0 ; PF=0
jnp odd_parity
; 8.9 辅助进位标志 (AF)
; 用于BCD运算
mov al, 0x0F
add al, 0x01 ; AF=1
daa ; 十进制调整
; 8.10 条件跳转指令
; 基于无符号比较
mov eax, 100
mov ebx, 200
cmp eax, ebx
ja above ; CF=0且ZF=0
jae above_equal ; CF=0
jb below ; CF=1
jbe below_equal ; CF=1或ZF=1
; 基于有符号比较
jg greater ; ZF=0且SF=OF
jge greater_equal ; SF=OF
jl less ; SF≠OF
jle less_equal ; ZF=1或SF≠OF
; 基于标志
jc carry_set ; CF=1
jnc no_carry ; CF=0
jz zero ; ZF=1
jnz not_zero ; ZF=0
js sign_negative ; SF=1
jns sign_positive ; SF=0
jo overflow ; OF=1
jno no_overflow ; OF=0
jp parity_even ; PF=1
jnp parity_odd ; PF=0
; 8.11 SETcc指令 - 根据条件设置字节
cmp eax, ebx
set
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐




所有评论(0)