; 2. for i=x/2 downto 2 do ; if x mod i=0 then {flag=0;break;} ; 注意合理的分配使用寄存器,ecx=i,兼做除数。 ; edx,eax做被除数,ebx=flag的地址,edi=x,用于暂存x push ebp mov ebp,esp ; 建立访问栈参数的指针基准 push eax ; 保护子程序中要使用的寄存器 push ebx push ecx push edx push edi mov ebx,[ebp+12] ;变量flag的地址 mov byte ptr [ebx],1 ;flag=1 mov eax,[ebp+8] ;eax=x mov edi,eax ;edi=x,用于暂存x mov ecx,eax shr ecx,1 ;ecx=x/2 .while (ecx>=2) mov eax,edi ;eax=x,注意:此句极易漏掉!导致逻辑错误。 xor edx,edx ;被除数送edx,eax,32位除法 div ecx ;div指令执行后eax=商,edx=余数 or edx,edx ;cmp edx,0 jnz next ;if eax mod ecx<>0 then goto next mov byte ptr [ebx],0 ;flag=0 jmp restore next: dec ecx .endw restore: pop edi ; 恢复子程序中使用过的寄存器 pop edx pop ecx pop ebx pop eax pop ebp ret 2*4 ;清理栈中的参数 prime endp end main ;end of assembly 11. 编程写一个名为Gcd的求两个数最大公约数子程序,主子程序间的参数传递通过堆栈完成。调用Gcd子程序求出三个双自变量:dvar1、dvar2与dvar3的最大公约数并输出。显示一个无符号数的子程序为:dispuid,入口参数:EAX=要显示无符号数的值。 ; Win32 Console Application ; 利用子程序求3个无符号整数的最大公约数。 ; 目的:学习子程序的构造与参数的传递方法。 31
.686 .model flat,stdcall option casemap:none includelib msvcrt.lib printf PROTO C : dword,:vararg .data dvar1 dword 2012 dvar2 dword 128 dvar3 dword 456 dgcd dword ? ;存放2个无符号整数的最大公约数 fmtStr byte ' gcd(%d,%d,%d)=%d',13,10,0 .code main proc push dvar1 push dvar2 ;参数dvar1,dvar2进栈,传值 push offset dgcd ;dgcd的地址进栈,传地址 call Gcd ;dgcd=dvar1,dvar2的最大公约数 push dvar3 push dgcd ;参数dvar3,dgcd进栈,传值 push offset dgcd ;dgcd的地址进栈,传地址 call Gcd invoke printf,offset fmtStr,dvar1,dvar2,dvar3,dgcd ret ;return to Windows main endp ;end of main Gcd proc ; function: 求2个无符号整数的最大公约数。 ; Receives: 从栈中获取无符号整数a,b及 ; 存放最大公约数变量gcd的地址 ; Returns: gcd=无符号整数a,b的最大公约数。 ; 注意:[ebp+8]是最后一个压入栈中的参数! ; 以[ebp+8]为基准,从栈中获取其它的参数。 ; 算法思想:采用欧几里得算法。gcd(a,0)=a; ; gcd(a,b)=gcd(b,a mod b) ; 算法描述: ; 1. while b<>0 do ; { r=a mod b;a=b;b=r;} ; 2. gcd=a; ; 注意合理的分配使用寄存器,edx,eax做被除数 ; ebx=gcd的地址,eax=a,ecx=b push ebp mov ebp,esp ; 建立访问栈参数的指针基准 push eax ; 保护子程序中要使用的寄存器 push ebx push ecx 32
push edx mov ebx,[ebp+8] ;ebx=变量gcd的地址 mov ecx,[ebp+12] ;ecx=b mov eax,[ebp+16] ;eax=a .while (ecx!=0) xor edx,edx ;被除数送edx,eax,32位除法 div ecx ;div指令执行后eax=商,edx=余数 mov eax,ecx ;a=b mov ecx,edx ;b=r,edx=余数 .endw mov [ebx],eax ;gcd=最大公约数 restore: pop edx ; 恢复子程序中使用过的寄存器 pop ecx pop ebx pop eax pop ebp ret 3*4 ;清理栈中的参数 Gcd endp ;end of Gcd end main ;end of assembly 12. 在一个已知长度的字符串中查找是否包含“BUG”子字符串。如果存在,显示“Y”,否 则显示“N”。 显示一个字符的子程序为:dispc,入口参数:AL=要显示个字符的SACII码。 ; Win32 Console Application ; 串模式匹配算法,求子串在源串中第一次出现的起始位置。 ; 若子串在源串中出现则显示“Y”,否则显示“N”。 ; 算法思想:采用人工串匹配的方法,就是从左向右扫描, ; 当源串没有结束时,从源串的第i个字符开始与子串进行比较, ; 若相等,则继续比较后续字符,否则从源串的第i+1 ; 个字符开始重新与字串进行比较。这种算法的效率非常低, ; 一种朴素串模式匹配算法改进的算法称为KMP算法。 ; 算法描述: ; 1. i=j=0; 数组下标从0开始,sStr为源串,tStr为子串 ; 2. while (i ; 采用相对寻址处理数组。 ; Q:若将此算法改为子程序,如何修改? Include io32.inc .data sStr byte 'If you find any error in the program, you can DEBUG it.' tStr byte 'BUG' sLen equ sizeof sStr tLen equ sizeof tStr .code main proc xor esi,esi ;i=esi mov edi,eax ;j=edi .while (esi