汇编实验

汇编实验

对应第五章内容及练习

最大公约数

求两个数的最大公约数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.data
val1 DWORD 120
val2 DWORD 36
.code
mov eax, val1
mov ebx, val2
L1:
mov edx, 0
div ebx ;余数在EDX,商在EAX
cmp edx, 0
je L2
mov eax, ebx ;除数做被除数
mov ebx, edx ;余数做除数
jmp L1
L2:
mov esi, ebx ;ESI返回最大公约数

需要注意一个问题就是EDX的值(被除数高位),每次计算时需要将其置零,否则容易导致结果溢出(存储商或者余数的寄存器无法放得下商或者余数)

压缩整数加法

课本例题:16位+16位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
INCLUDE Irvine32.inc
.data
packed_1 WORD 4536h ;4536
packed_2 WORD 7207h ;7207
sum DWORD ?
.code
main PROC
;初始化数组和索引
mov sum, 0
mov esi, 0
;低字节相加
mov al, BYTE PTR packed_1[esi]
add al, BYTE PTR packed_2[esi]
daa
mov BYTE PTR sum[esi], al
;高字节相加
inc esi
mov al, BYTE PTR packed_1[esi]
add al, BYTE PTR packed_2[esi]
daa
mov BYTE PTR sum[esi], al
;若还有进位,加上进位
inc esi
mov al, 0
adc al, 0
mov BYTE PTR sum[esi], al
;16进制显示和数
mov eax, sum
call WriteHex
call Crlf
call WaitMsg
exit
main ENDP
END main

结果就是压缩10进制的显示(16进制的11743)

课后拓展:同长度的任意位相加

扩展上面的程序,使其实现两个任意大小(但长度相同)的压缩十进制数加法,假设该过程使用如下寄存器传递参数:
ESI————第一个数的指针
EDI————第二个数的指针
EDX————和数的指针
ECX————相加的字节数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
INCLUDE Irvine32.inc

.data
packed1_1 WORD 4536h
packed1_2 WORD 7207h
packed2_1 DWORD 123456h
packed2_2 DWORD 234567h
packed3_1 BYTE 56h
packed3_2 BYTE 41h
sum DWORD ?


.code
main PROC
mov edx, OFFSET sum

mov esi, OFFSET packed1_1
mov edi, OFFSET packed1_2
mov ecx, TYPE packed1_1
call AddPacked
mov sum, 0

mov esi, OFFSET packed2_1
mov edi, OFFSET packed2_2
mov ecx, TYPE packed2_1
call AddPacked
mov sum, 0

mov esi, OFFSET packed3_1
mov edi, OFFSET packed3_2
mov ecx, TYPE packed3_1
call AddPacked
call WaitMsg
exit
main ENDP

AddPacked PROC
push ebx
mov ebx, 0
L1:
mov al, BYTE PTR [esi+ebx]
add al, BYTE PTR [edi+ebx]
daa
mov BYTE PTR [edx+ebx], al
inc ebx
loop L1

mov al, 0
adc al, 0
mov BYTE PTR [edx+ebx], al
;16进制显示和数
mov eax, [edx]
call WriteHex
call Crlf
pop ebx
ret
AddPacked ENDP
END main

没啥困难的,注意几个点:
过程定义要定义在.code下,别定义到外面去了
mov [esi], 0 报错而直接mov内存和立即数是可以的,而间接寻址的内存却不可以,不知道为啥-_-||

位元乘法

编写名为BitwiseMultiply的过程,仅使用移位和加法实现任意32位无符号数与EAX相乘,过程用EBX寄存器传递参数,用EAX寄存器传递返回值。假设乘积不会超过32位。
提示:一种可能的方法是用循环结构右移乘数,记录在进位标志被置1之前移动的位数,然后把这个位数用到SHL指令中,被乘数作为该指令的目的操作数。重复该过程直到乘数最后一个为1位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
INCLUDE Irvine32.inc
.data
val1 DWORD 4536h
val2 DWORD 2207h
.code
main PROC
mov eax, val1
mov ebx, val2
mov ecx, 32
mov edx, 0 ;结果保存在EDX中
L1:
ror ebx, 1 ;循环位移
jnc L2 ;非1时跳转
add edx, eax ;为1时相加
L2:
shl eax, 1 ;左移1位
loop L1
mov eax, edx
call WriteHex
call Crlf

mov eax, val1
mov ebx, val2
mul ebx
call WriteHex
call Crlf
call WaitMsg
exit
main ENDP
END main

经用标准乘法验证正确,这里我优化了一下,每次循环都让eax移位一次,而只有当CF=1时才让edx和eax相加,写起来就简练很多


复杂的带符号乘除混合运算——2019.11.14补充

若x,y,z,v均为16位带符号数,计算(v-(x*y+z–540))/x

  • 法一:我的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.data 
X DW 1200H
Y DW 0034H
Z DW 0F045H
W DW 034AH

.code
main PROC
xor eax, eax
xor edx, edx
mov dx, 0
mov ax, X
imul Y
add ax, Z
;考虑进位, 对高位+cf和0
adc dx, 0
sub ax, 540
;考虑退位,对高位-cf和0
sbb dx, 0
;求补码,减法变成加法
neg dx
neg ax
add ax, W
;同上考虑进位情况
adc dx, 0
idiv X
  • 法二:标答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
;省略.code和main声明
.data
MOV AX, X
IMUL Y ; x*y ->(DX,AX)
MOV CX, AX ; 临时保存ax
MOV BX, DX ; 临时保存dx
MOV AX, Z
CWD ; Z ->(DX,AX)
ADD CX, AX
ADC BX, DX ; x*y+z ->(BX,CX)
SUB CX, 540
SBB BX, 0 ; x*y+z-540
MOV AX, W
CWD ; W ->(DX,AX)
SUB AX, CX
SBB DX, BX ; w-(x*y+z-540)
IDIV X ; (w-(x*y+z-540))/x->(AX)余数->(DX)

Author

Ctwo

Posted on

2019-08-04

Updated on

2020-10-25

Licensed under

Comments