32位汇编:实验5算数运算类指令使用

1. 二进制数运算

(1)题目的具体要求,将原始数据及存放结果的内存单元分别定义成字变量或字节变量。

(2)编辑程序,把编写好的源程序建立为汇编语言源程序文件并存盘。

(3)对源程序文件进行汇编、连接,且修改至无错误,然后运行程序。

(4)利用调试程序观察运行结果。如果有错,分析并找出错误原因,改写程序并重新调试。

运行示例

复制代码
.386
.model flat, stdcall
option casemap:none

include windows.inc
include kernel32.inc
include user32.inc
include masm32.inc

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib

	.data
	A DW 23579           
	B DW 7684            
	bC DB 0A5H 
	D DB 34H 
	E DW ?               
	G DB ? 

	fmt db "23579 + 7684 = %d", 13, 10
        db "0A5H + 34H = %02XH", 13, 10, 0
    buffer db 128 dup(0)

	.code
start:
	MOV ax,A
	ADD ax,B
	MOV E,ax
	
	MOV AL,bC
	ADD AL,D       
	MOV G,AL

	;结果格式化输出
	movzx EAX,G
	push EAX
	movzx EAX,E
	push EAX
	push offset fmt
	push offset buffer
	call wsprintf
	add esp,16

	push 0
	push offset caption
	push offset buffer
	push 0
	call MessageBoxA

	push 0
	call  ExitProcess
	
	caption DB "二进制运算结果",0

end start

我们发现编译为乱码,排查发现是源代码文件编码与系统期望的编码不匹配,更改文件编码后解决。

调试器进行验证

MOV ax,A

ADD ax,B

MOV E,ax

MOV AL,bC

ADD AL,D

MOV G,AL

经验证结果一致。

2. 多字节加法

(1)在FIRST和SECOND开始的内存单元中建立各为10位的压缩型BCD码的数据区,数据要选择得当。要考虑位间有进位和最高位也要有进位等不同情况。数据从低字节开始存放。

(2)把编写好的源程序,用编辑程序建立为汇编语言程序源文件并存盘。

(3)注意多字节运算加法指令的选择以及相应状态(如CF位)位的设置。进行BCD码运算时,要选择合适的十进制调节调整指令;运算结果的最高位进位情况要处理。

(4)汇编、连接源程序,且修改至无错误,然后运行程序。

知识回顾

多精度加法

多精度加法用于处理超过32位的整数运算(eg:64,128位甚至高精度整数)

因为寄存器最多为32位,因此需要分字节或分字处理,并手动处理CF(进位标志)

概念 说明
DAA 指令 加法后调整 AL 为压缩 BCD 格式(仅限 AL 寄存器)
ADC 指令 带进位加法,用于多字节加法
小端序 低位字节存在低地址,符合 x86 内存布局

压缩BCD

每字节含两位BCD数字

高4bit = 十位,低4bit = 个位,范围0-99(即0x00-0x99) • 示例:46H = 01000110b 表示BCD码46

运算后某位>9或半进位AC=1,必须立即DAA/DAS调整,否则报错。

  • 两个 10 位压缩 BCD 数(共 5 字节),低位在前
  • 相加后结果存入 THIRD,最多 11 位(6 字节,含进位)

x86 提供的十进制调整指令:

DAA ------ 加法后把 AL 调整为压缩 BCD(仅影响 AL,且只对 ADD/ADC 有效)。

DAS ------ 把AL调整成合法BCD,并减6校正。

这两条指令只认 AL,因此循环必须以字节为单位处理。

ADD后必须紧跟DAA,中间不能插入任何改变AL或标志的指令。

若CF=1表示向高位产生了进位(100以上)

运行示例

复制代码
	include io32.inc
	.data
FIRST DB 46H,58H,32H,71H,66H,0H 
SECOND DB 75H,21H,49H,23H,82H,0H
THIRD DB 6 DUP(?) 
	.code
start:
	MOV ECX,6
	MOV ESI,0
	CLC
LLO: 
    MOV AL,SECOND[ESI] 
	ADC AL,FIRST[ESI] 
	DAA
	MOV THIRD[ESI],AL
	INC ESI
	LOOP LLO
	exit 0
	end start

调试器验证

复制代码
MOV CX,6
MOV ESI,0
CLC

存储清零

复制代码
MOV AL,SECOND[ESI] 
ADC AL,FIRST[ESI] 
DAA
MOV THIRD[ESI],AL
INC ESI
LOOP LLO

第一次循环相加中出现了进位CF=1

第一次循环结束后cx-1,EIP进入第二次循环位置

此后循环依次执行,我们发现该代码并没有直接退出循环,问题为ECX≠0,我们只把CX置0,修改后程序正常6此后退出循环,得到我们相加后的数值

最终结果为014894818021,验证成功

3. 二进制乘法

(1)选择相应的数据存放于内存单元中。为了考查多种情况,数据选择要合理。对于8位无符号数应使其在0~255的范围内,并使得积大于8位无符号数的范围;对于16位有符号数的选择应兼顾到正、负数的情况。注意乘法指令的选择要考滤有符号乘法和无符号乘法的不同情况;有符号乘数如果为负数,则数据在内存中以二进制补码形式存放。

知识回顾

乘法指令一览

无符号

MUL r/m8 ; AX ← AL * r/m8

MUL r/m16 ; DX:AX ← AX * r/m16

MUL r/m32 ; EDX:EAX ← EAX * r/m32

有符号

IMUL r/m8 ; AX ← AL * r/m8

IMUL r/m16 ; DX:AX ← AX * r/m16

IMUL r/m32 ; EDX:EAX ← EAX * r/m32

规则:

  • 源操作数 × 累加器(AL/AX/EAX)→ 双倍宽度结果。
  • 结果高半部永远放在 AH/DX/EDX,低半部放在 AL/AX/EAX。
  • CF/OF 置位表示"高半部非 0(无符号)或符号扩展失败(有符号)",其他标志未定义。

8 位无符号要点

被乘数必须预先装 AL,乘数可为内存字节或寄存器。

结果 16 位,在 AX 中,直接 mov [mem],ax 即可。

16 位带符号要点

被乘数必须预先装 AX,乘数可为内存字或寄存器。

结果 32 位,高 16 位在 DX,低 16 位在 AX。由于 Win32 内存按 32 位对齐方便,可一次把 DX:AX 存到连续 4 字节。

符号扩展与高位丢弃若只关心完整 32 位结果,无需理会 CF/OF;若需 64 位结果,可用 32 位 IMUL 产生 EDX:EAX。

MASM32 内存声明字节用 db,字用 dw,双字用 dd;带符号十进制字面量直接写,如 -12345,MASM 会自动按 16 位补码编码。

运行示例

复制代码
	include io32.inc
	.data
	DATA1 DB 245 
	DATA2 DB 43 
	DATA3 DW ?
	FIRST DW 6405H 
	SECOND DW 0FFFEH 
	THIRD DW ?
	THIRD1 DW ?
	.code
start:
	MOV AL,DATA1
	MUL DATA2
	MOV DATA3,AX 
	MOV AX,FIRST
	IMUL SECOND
	MOV THIRD,AX
	MOV THIRD1,DX
	exit 0
	end start

调试器验证

无符号数

复制代码
MOV AL,DATA1
MUL DATA2

我们可以看出ax值正确

有符号乘法

复制代码
MOV AX,FIRST
IMUL SECOND

我们可以看出结果正确

相关推荐
伐尘2 小时前
【汇编】RAX,eax,ax,ah,al 关系
汇编
CHANG_THE_WORLD3 小时前
c语言位运算 汇编代码分析
c语言·开发语言·汇编
CHANG_THE_WORLD3 小时前
if条件语句 三目运算符 汇编分析
汇编·算法·条件语句·if 语句·汇编分析·条件语句汇编分析
CHANG_THE_WORLD1 天前
有符号数和无符号数的 汇编视角 区别
汇编
南飞测绘视界2 天前
【编号220】中国国内生产总值历史数据汇编1952-2021合订本(PDF扫描版)
汇编·pdf·年鉴
Ayanami_Reii4 天前
汇编和C语言结构
c语言·汇编·笔记
脑子慢且灵6 天前
C语言与Java语言编译过程及文件类型
java·c语言·开发语言·汇编·编辑器
日更嵌入式的打工仔10 天前
汇编与反汇编
汇编
oioihoii15 天前
从汇编角度看C++优化:编译器真正做了什么
java·汇编·c++