X86汇编-分支、循环与子程序综合作业

1. 编写完整程序,通过API输入三个不同的正整数,然后编程求解这三个数的中间数,即大小在三个数中间的那个数,将其输出。

高级语言特性用起来!

六个判断就可以解决所有情况,代码如下

    .386
.model flat,stdcall
option casemap:none
include Stdlib.Inc
includelib Stdlib.lib
include kernel32.inc
includelib kernel32.lib

.data
a dd 0
b dd 0
d dd 0
tip db 'The middle number is '
result dd 0

.code
.startup CONSOLE
invoke Readln,offset a,offset a,16
invoke Readln,offset b,offset b,16
invoke Readln,offset d,offset d,16
mov eax,a
mov ebx,b
mov edx,d
.if (eax>=ebx)&&(eax<=edx)
mov result,eax
.elseif (eax>=ebx)&&(ebx>=edx)
mov result,ebx
.elseif (ebx>=eax)&&(ebx<=edx)
mov result,ebx
.elseif (ebx>=eax)&&(eax>=edx)
mov result,eax
.elseif (edx>=eax)&&(edx<=ebx)
mov result,edx
.else
mov result,edx
.endif
invoke Writeln,offset tip
;invoke Writeln,offset result

.exit 0

运行结果为

img

2. 编写完整程序,首先编写一个子程序,用于比较两个字符串是否相等,其参数是两个字符串的首地址(字符串用字节 0 结束),返回值为0时表示相等,否则返回值为两个字符串中第一次不匹配的字符偏移,该子程序的定义与标准C函数 strcmp 相同。然后编写主程序,首先输入两个字符串,如果相同则输出 "Equal" ,不相同则输出 "Unequal" 。

主要思路是在子程序中实现逐字符比对,其核心在于len值的变换,对于其数值在不同条件下的判断还是需要花一些心思,核心代码已注释,如下所示

    .386
.model flat,stdcall
option casemap:none
include Stdlib.Inc
includelib Stdlib.lib
include kernel32.inc
includelib kernel32.lib

.data
equal db 'Equal',0
unequal db 'Unequal',0
s1 db 64 dup(0)
s2 db 64 dup(0)
len1 dd 0
len2 dd 0
len dd 0


.code
s_cmp proc
push eax
push ebx
mov edi,0
mov esi,0
mov cl,s1[edi]
mov dl,s2[esi]
.if cl!=dl
inc len ;第一个就不匹配直接加一输出
.else
.while (cl==dl)&&(cl!=0)&&(dl!=0) ;依次比对字符
mov cl,s1[edi]
mov dl,s2[esi]
inc edi
inc esi
.if (len==eax)&&(len==ebx) ;完全匹配则跳转结束,防止再次加1
mov len,0
jmp s_eq
.endif
inc len ;持续记录匹配的数量
.endw
.endif
s_eq: pop ebx
pop eax
ret
s_cmp endp

.startup CONSOLE
invoke Readln,offset s1,offset s1,32
mov len1,eax
invoke Readln,offset s2,offset s2,32
mov len2,eax
mov eax,len1
mov ebx,len2
call s_cmp
invoke DwToStr,len,offset len
invoke Writeln,offset len
.exit 0

运行结果概览:

相等时输出0

img

不相等输出第一个不相等的偏移

img

img

可谓非常完美

3. 编写完整程序,首先编写子程序,将寄存器 EAX 中存储的数值转换为10进制表示的字符串,参数为寄存器EAX和字符串缓冲区的首地址,无返回值。然后在主程序中给 EAX 赋一个任意值,调用子程序,并将字符串输出。

此题其实很简单,但我却花了很大心思,主要是对DwToStr这一函数了解不深

原本我的想法是把eax的位/10,余数一个一个压栈,然后一个一个pop出来相加成16,最后再输出

eax_s   proc
push eax
mov edx,0
mov bx,-1
push bx
mov bx,10

stack_in:
xor dx,dx
div bx
mov cx,ax
or cx,dx
jz stack_out
push dx
jmp stack_in

stack_out:
pop dx
cmp dx,-1
jz  exit
add result,edx
shl result,4
jmp stack_out

exit: pop eax
ret
eax_s endp

其实这一切通过DwToStr这一函数就可以完全完成题目所示的任务

    .386
.model flat,stdcall
option casemap:none
include Stdlib.Inc
includelib Stdlib.lib
include kernel32.inc
includelib kernel32.lib

.data
a dd 0
result1 db 32 dup(0)
result2 dd 0
tip1 db 'EAX中十六进制表示如下:',0
tip2 db '转为十进制对应数值如下:',0

.code
eax_s proc
invoke DwToStr,a,offset result2
ret
eax_s endp

eax_hex proc
invoke DwToHex,a,offset result1
ret
eax_hex endp

.startup CONSOLE
invoke Readln,offset a,offset a,32
mov eax,a
call eax_hex
invoke Writeln,offset tip1
invoke Writeln,offset result1
call eax_s
invoke Writeln,offset tip2
invoke Writeln,offset result2
.exit 0

运行效果如下

img

与在线十六进制转十进制的结果比对

img

没有问题

所以DwToStr可以实现十六进制数的十进制值输出

DwToHex可以实现十六进制数的原本输出

这两个函数里面是对ASCII码的复杂变换

4. 编写完整程序,首先输入两个不同整数,然后基于以下C代码设计求解两个整数的最大公约数,并将其输出。求解最大公约数的C代码如下:

int GCD(int x, inty) { 
   x = abs(x); // x的绝对值
   y = abs(y);
   do{ int n = x % y; // 取模运算,即除法的余数
      x = y;
      y = n;
    }
   while(y > 0)
       return x;
}

这个题目有两个关键点

第一个是键盘输入的是ASCII码,需要转为对应的十六进制,而StrToDw可以将EAX置为对应的值

第二个是关于div的使用

img

每次得到edx后应该将其清零,否则会和eax组成64位的数继续运算产生除法错中断

    .386
.model flat,stdcall
option casemap:none
include Stdlib.Inc
includelib Stdlib.lib
include kernel32.inc
includelib kernel32.lib

.data
a dd 0
b dd 0
abs =7FFFh
.code

.startup CONSOLE
invoke Readln,offset a,offset a,8
invoke Readln,offset b,offset b,8
invoke StrToDw,offset a ;将ASCII码对应的值转为十六进制表示
mov a,eax
invoke StrToDw,offset b
mov b,eax
and a,abs
and b,abs
mov edx,0
.repeat
mov eax,a
mov ebx,b
div ebx
mov a,ebx
mov b,edx
mov edx,0 ;这句话相当重要,否则出现edx与eax共同组成被除数,引发除法错中断
.until b==0
invoke DwToStr,a,offset a
invoke Writeln,offset a

.exit 0

运行结果为

img

img

多组测试均无问题

posted @ 2022-04-02 23:13  Xiaohanahahah  阅读(196)  评论(0编辑  收藏  举报