字符串操作实践[内联汇编实现]
2012-04-09 20:52
211 查看
以下代码在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;
}
函数实现:
[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;
}
相关文章推荐
- 字符串操作实践[内联汇编实现]
- 《面向对象程序设计与VC++实现》--liwei_2_1(字符串基本操作 求长度、复制、连接)
- 用字符串来实现加1操作
- c语言实现字符串的各种操作
- 模拟实现字符串操作函数
- 纯C 字符串操作函数 实现 (strcpy, strncpy, memcpy, memset, strcat, strlen ... )
- 单链表操作,队列,栈实现,以及常见字符串库函数经典实现
- //4. 编写一个函数reverse_string(char * string)(递归实现) //实现:将参数字符串中的字符反向排列。 //要求:不能使用C函数库中的字符串操作函数。
- c中利用字符串操作实现用户自己输入文件名
- shell 如何实现i++操作以及字符串截取操作
- Python 切片:利用切片操作,实现一个trim()函数,去除字符串首尾的空格
- C的字符串操作接口实现
- 纯C 字符串操作函数 实现 (strcpy, strncpy, memcpy, memset, strcat, strlen ... )
- 字符串操作的几个经典实现
- c中利用字符串操作实现用户自己输入文件名
- C++ string类字符串的常用操作及实现
- 【C语言】编写一个函数reverse_string(char * string) 实现:将参数字符串中的字符反向排列。要求:不能使用C函数库中的字符串操作函数。
- 如何用Python高效实现下面这样的字符串拼接操作?
- 自己实现的字符串操作函数
- Retrofit 2.0 超能实践(三),轻松实现文件/多图片上传/Json字符串