以下代码在VC6下编译测试通过 函数实现: /***********************************************************************/ /* 比较两个字符串是否相等 */ /**********************************************************************/ bool isEqual(const char * str1,const char * str2) { // if (strlen(str1)!=strlen(str2)){//长度不相等则不相等 // return false; // } //对上面判断语句的汇编实现 __asm { push [ebp+0x8] //str1地址入栈 call strlen //调用c函数获取长度 add esp,4 //堆栈平衡[c调用约定"__cdecl"规定由函数的调用者释放堆栈] mov ebx,eax //存放比较结果,为了避免后面再次调用strlen函数引起返回值覆盖[函数的返回值规范约定保存在eax里面] push [ebp+0xc] //str2地址入栈 call strlen //调用c函数获取长度[函数的返回值规范约定保存在eax里面] add esp,4 //堆栈平衡[c调用约定"__cdecl"规定由函数的调用者释放堆栈] cmp eax,ebx //比较两个字符串的长度 jne exit2 //不相等则跳转到 exit2 } // for (;str1<str1+strlen(str1);str1++,str2++)//循环比较每个字符是否相等,如果某个字符不相等那么整个也不相等 // { // if (*str1!=*str2){ // return false; // } // } //对上面for循环的汇编实现 __asm { push [ebp+8] //str1地址入栈 call strlen //调用c函数获取长度 add esp,4 //堆栈平衡[c调用约定"__cdecl"规定由函数的调用者释放堆栈] mov esi,[ebp+8] //取str1地址到esi寄存器 mov edx,esi //复制到edx寄存器 mov edi,[ebp+0xc] //取str2地址到edi寄存器 imul eax,type char //计算指针偏移量[eax中存放的是strlen的返回值,str1是字符指针,对指针做算术运算时参与运算的值是它所指向的类型的长度] add edx,eax //计算循环上限[str1+strlen(str1)] beginfor: cmp esi,edx //比较[str1<str1+strlen(str1)] jnl endfor //如果不小于那么结束循环[当然也可以用"大于等于"跳转指令] mov bl,byte ptr [esi] //取str1的一个字符到bl寄存器 mov cl,byte ptr [edi] //取str2的一个字符到cl寄存器 cmp bl,cl //比较两个字符大小 jne exit2 //不相等则结束 add esi,type char //str1指针向前移动 add edi,type char //str2指针向前移动 jmp beginfor //跳转到beginfor继续循环 endfor: } __asm { exit1: mov eax,1 //返回相等[return true] jmp exit //结束 exit2: mov eax,0 //返回不相等[return false] exit: //程序结束 } } 测试: #include "stdafx.h" #include "string.h" bool isEqual(const char * ,const char *); extern "C" void _stdcall startWith(const char *,const char *,bool *); extern "C" int __stdcall ncompare(int,int); int main(int argc, char* argv[]) { __asm { mov eax,eax mov eax,eax } char * course1 = "java5"; char * course2 = "java6"; char * msg1 = "不相等"; char * msg2 = "相等"; // if (::strcmp(course1,course2)) // { // // printf("不相等"); // } // else // { // printf("相等"); // } // bool ret = isEqual(course1,course2); // if (ret) // { // printf("相等"); // } // else // { // printf("不相等"); // } //调用自定义的函数 __asm { push course2 //传递第2个参数 push course1 //传递第1个参数 call isEqual //调用函数[VC编译器默认采用c调用约定"__cdecl"] add esp,8 //堆栈平衡[c调用约定"__cdecl"规定由函数的调用者释放堆栈] test eax,eax //eax是上面函数调用的返回值,对eax本身进行与操作[只影响标志位,不影响寄存器本身],检查其值是否为 0 je local1 //je等同于jz,如果eax的值是0[说明返回的是false],那么与结果值为0,则zf=1,则函数调用的 返回的值是false[不相等] push msg2 //相等,msg2地址入栈[向printf传递参数] call printf //调用c函数prinf输出 add esp,4 //堆栈平衡 jmp local2 //程序结束 local1: push msg1 //不相等,msg1地址入栈[向printf传递参数] call printf //调用c函数prinf输出 add esp,4 //堆栈平衡 local2: } return 0; } 测试字符串是否以某个子字符串开始 函数: /************************************************************************/ /*检查是否以prefix开始 */ /* content:整个字符串 */ /* prefix: 要查找的字符串 */ /* result: 返回的值 */ /************************************************************************/ void _stdcall startWith(const char * pContent,const char * pPrefix,bool * pResult) { // if (pContent==NULL || pPrefix == NULL || strlen(pContent)<strlen(pPrefix)) // { // *pResult = false; // return; // } /** 当前堆栈情况 0x12FEEC: 0012FF80 //进入当前方法前的EBP的值 +0x4 0040D9CC //当前方法的返回地址 +0x8 0012FF70 //传递给当前方法的第一个参数PContent +0xc 0012FF68 //传递给当前方法的第二个参数pPrefix +0x10 0012FF50 //传递给当前方法的第三个参数pResult */ //验证执行条件 __asm { cmp [ebp+8],0 //验证pContent je exitwithfalse //为0则退出 cmp [ebp+0xc],0 //验证pPrefix je exitWithfalse //为0则退出 push [ebp+8] //strlen(pContent)-->ebx call strlen; add esp,4 mov ebx,eax push [ebp+0xc] //strlen(pPrefix)-->eax call strlen add esp,4 cmp ebx,eax //strlen(pContent)<strlen(pPrefix) jl exitwithfalse } const char * pp = pPrefix; const char * pc = pContent; // for (; pp<pPrefix+(strlen(pPrefix)*sizeof(char)); pp++,pc++) // { // if (*pp!=*pc) // { // *pResult = false; // return; // } // } //以下是循环的代码实现 __asm { push [ebp+0xc] //strlen(pPrefix) call strlen add esp,4 // imul eax,type char //strlen(pPrefix)*sizeof(char) mov edi,pPrefix add edi,eax //pPrefix+strlen(pPrefix)*sizeof(char) beginfor: cmp pp,edi //if (pp<pPrefix+strlen(pPrefix)*sizeof(char)) jnl exitwithtrue //不满足循环条件则退出循环 mov eax,pp mov al,byte ptr [eax] //*pp-->al mov ebx,pc mov bl,byte ptr [ebx] //*pc-->bl cmp al,bl //if (*pp!=*pc) jne exitwithfalse //发现不通的字符则退出循环 add pp,type char //pp++ add pc,type char //pc++ jmp beginfor //继续下一轮循环 } //*pResult =true; __asm { endfor: jmp exitwithtrue } __asm { exitwithfalse: mov eax,[ebp+0x10] mov [eax],0 //*pResult=0 jmp exit exitwithtrue: mov eax,[ebp+0x10] mov [eax],1 //*pResult=1 exit: //退出 } } 测试代码: int main(int argc, char* argv[]) { char content[] = "welcome to you"; char prefix[] ="welcome"; char msg1[] = "包含"; char msg2[] = "不包含"; char fmt[] = "%s/n"; bool result = false; bool * pResult = &result; // startWith(content,prefix,&result); // printf("%s/n",result?"包含":"不包含"); //以下是汇编实现版本 __asm { push pResult //传递第三个参数 lea eax,prefix //传递第二个参数--取数组首地址 push eax //传递第二个参数 lea eax,content //传递第一个参数--取数组首地址 push eax //传递第一个参数 call startWith //调用函数[该函数采用__stdcall约定,将由北调用函数自身负责堆栈的平衡] cmp result,1 //比较结果是否为1[true] je processeq; //如果为1说明包含,跳转到processeq处理显示包含信息 lea eax,msg2 //否则说明不包含--取msg2数组首地址 push eax //否则说明不包含--传递第二个参数 lea eax,fmt //传递第一个参数--取数组fmt首地址 push eax //传递第一个参数 call printf //调用函数输出信息 add esp,8 //堆栈平衡 jmp exit //程序结束 processeq: //处理包含的情况 lea eax,msg1 //取数组msg1的首地址 push eax //第二个参数入栈 lea eax,fmt //去数组fmt的首地址 push eax //第一个参数入栈 call printf //调用函数输出信息 add esp,8 //堆栈平衡 exit: //程序结束 } return 0; }