您的位置:首页 > 其它

字符串操作实践[内联汇编实现]

2012-04-09 20:52 169 查看
以下代码在VC6下编译测试通过
函数实现:

[cpp]
view plaincopyprint?

/***********************************************************************/
/* 比较两个字符串是否相等 */
/**********************************************************************/
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: //程序结束
}

}

测试:

[cpp]
view plaincopyprint?

#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;
}

测试字符串是否以某个子字符串开始

函数:

[cpp]
view plaincopyprint?

/************************************************************************/
/*检查是否以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: //退出
}
}

测试代码:

[cpp]
view plaincopyprint?

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: