为了打牢基本功,重写部分C库函数(参考C库与别人的代码,并给出了测试代码),并对部分进行反汇编分析(用VC自带反汇编和OD)。在写程序过程中,会仔细验证很多以前模棱两可的知识点。
1.
/*从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
1.source和destin所指内存区域不能重叠,函数返回指向destin的指针。
2.与strcpy相比,memcpy并不是遇到'\0'就结束,而是一定会拷贝完n个字节。
3.source和destin都不一定是数组,任意的可读写的空间均可
*/
#include "stdafx.h"
#include <afxcom_.h>
void pmemcpy(void *dest,void *src,int n);
int main(int argc, char* argv[])
{
//printf("Hello World!\n");
char *a1="abc\0def";
char a2[6];
printf("a1=%s,a2=%s\n",a1,a2);
pmemcpy(a2,a1,5);
for (int i=0;i<6;i++)
{
printf("%c",a2[i]);
}
printf("\n");
return 0;
}
void pmemcpy(void *dest,void *src,int n)
{
ASSERT((dest!=NULL)&&(src!=NULL));
//assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行
char *tmp_dest=(char *)dest;
char *tmp_src=(char *)src;
while (n--)
{
*tmp_dest=*tmp_src++;
tmp_dest++;
}
}
ps:对于a2[6]的初始化,a2[6]={0},将a2[0]初始化为0后,其余的各位也自动补0初始化,用printf("%s",a2)打印将不显示出。但是很奇怪printf("%s",a2[0]);打印出来<NULL>。按理说a2与a2[0]应该是指向同一处地址;为什么打印结果不同呢。
反汇编分析:
debug方式编译,VC自带反汇编工具分析:
17: int main(int argc, char* argv[])
15: {
00401020 push ebp //保护启动函数的ebp值,将其入栈
00401021 mov ebp,esp //ebp、esp同时指向栈底
00401023 sub esp,50h //esp-50h,留出main函数栈空间(分配给变量)
00401026 push ebx
00401027 push esi
00401028 push edi //将ebx、esi、edi入栈
00401029 lea edi,[ebp-50h] //通过ebp寻址
0040102C mov ecx,14h //为下面初始化刚刚留出的栈空间做准备,ecx作为循环填充的次数,50h/4=14h;
00401031 mov eax,0CCCCCCCCh //要填充的值
00401036 rep stos dword ptr [edi] //进行填充
char *a1="abc\0def";
00401038 mov dword ptr [ebp-4],offset string "abc\0def" (00422034)
//00422034为“abc\0def”字符串的索引地址
18: char a2[6];
19: printf("a1=%s,a2=%s\n",a1,a2);
0040103F lea eax,[ebp-0Ch]
//通过ebp-0ch索引变量a2,放入eax中
00401042 push eax
//将变量eax(a2)入栈(函数main的栈)(参数入栈顺序为从右往左)
00401043 mov ecx,dword ptr [ebp-4]
00401046 push ecx
//同上将参数a1入栈
00401047 push offset string "a1=%s,a2=%s\n" (00422024)
//通过字符串索引将第一个参数入栈
0040104C call printf (004011b0)
//调用函数(跟进函数printf内部)
00401051 add esp,0Ch
//堆栈平衡原理,调用者自己清理堆栈
20: pmemcpy(a2,a1,5);
//又是一个函数调用,不解释,参考上面
00401054 push 5
00401056 mov edx,dword ptr [ebp-4]
00401059 push edx
0040105A lea eax,[ebp-0Ch]
0040105D push eax
0040105E call @ILT+0(pmemcpy) (00401005)
00401063 add esp,0Ch
21: for (int i=0;i<6;i++)
00401066 mov dword ptr [ebp-10h],0
//初始化变量i
0040106D jmp main+58h (00401078)
//跳转去00401078地址
0040106F mov ecx,dword ptr [ebp-10h]
//将i存到ecx中
00401072 add ecx,1
// i+1
00401075 mov dword ptr [ebp-10h],ecx
// i+1后的值存回变量地址中
00401078 cmp dword ptr [ebp-10h],6
//将I与6进行比较
0040107C jge main+76h (00401096)
//>=则跳
22: {
23: printf("%c",a2[i]);
//同上,不解释.....
0040107E mov edx,dword ptr [ebp-10h]
00401081 movsx eax,byte ptr [ebp+edx-0Ch]
00401086 push eax
00401087 push offset string "%c" (00422020)
0040108C call printf (004011b0)
00401091 add esp,8
24: }
00401094 jmp main+4Fh (0040106f)
25: printf("\n");
00401096 push offset string "\n" (0042201c)
0040109B call printf (004011b0)
004010A0 add esp,4
26: return 0;
004010A3 xor eax,eax
27: }
void pmemcpy(void *dest,void *src,int n)
30: {
004010F0 push ebp
004010F1 mov ebp,esp
004010F3 sub esp,48h
004010F6 push ebx
004010F7 push esi
004010F8 push edi
004010F9 lea edi,[ebp-48h]
004010FC mov ecx,12h
00401101 mov eax,0CCCCCCCCh
00401106 rep stos dword ptr [edi]
31: ASSERT((dest!=NULL)&&(src!=NULL));
00401108 cmp dword ptr [ebp+8],0
//将第二个参数与0进行比较(仔细想想为什么是bep+8来索引的呢?)
0040110C je pmemcpy+24h (00401114)
//=0,则跳到00401114开始执行(其实就是打印一条出错信息,并结束程序)
0040110E cmp dword ptr [ebp+0Ch],0
//将第三个参数与0进行比较
00401112 jne pmemcpy+48h (00401138)
//
!=则跳
00401114 push 0
00401116 push 0
00401118 movsx eax,word ptr [`pmemcpy'::`2'::__LINE__Var (00424a30)]
0040111F add eax,1
00401122 push eax
00401123 push offset string "D:\\c\xbf\xe2\xba\xaf\xca\xfd\xd6\xd8\xd0\xb4\xc4\xbf\xc2\xbc\\memcpy\\me
00401128 push 2
0040112A call _CrtDbgReport (00401380)
0040112F add esp,14h
00401132 cmp eax,1
00401135 jne pmemcpy+48h (00401138)
00401137 int 3
00401138 xor ecx,ecx
//应该是检验&&
0040113A test ecx,ecx
0040113C jne pmemcpy+18h (00401108)
32:
33: char *tmp_dest=(char *)dest;
0040113E mov edx,dword ptr [ebp+8]
00401141 mov dword ptr [ebp-4],edx
34: char *tmp_src=(char *)src;
00401144 mov eax,dword ptr [ebp+0Ch]
00401147 mov dword ptr [ebp-8],eax
35:
36: while (n--)
0040114A mov ecx,dword ptr [ebp+10h]
//变量n存放到ecx
0040114D mov edx,dword ptr [ebp+10h]
//变量n存放到eax
00401150 sub edx,1
//edx-1
00401153 mov dword ptr [ebp+10h],edx
//将n-1存到变量n的地址中
00401156 test ecx,ecx
//检测ecx是否为0(即n是否等于0了)
00401158 je pmemcpy+88h (00401178)
// n=0,则跳出循环
37: {
38: *tmp_dest=*tmp_src++;
0040115A mov eax,dword ptr [ebp-4]
0040115D mov ecx,dword ptr [ebp-8]
00401160 mov dl,byte ptr [ecx]
//将ecx中的值按字节存入dl寄存器中(指针取值运算)
00401162 mov byte ptr [eax],dl
00401164 mov eax,dword ptr [ebp-8]
00401167 add eax,1
0040116A mov dword ptr [ebp-8],eax
39: tmp_dest++;
0040116D mov ecx,dword ptr [ebp-4]
00401170 add ecx,1
00401173 mov dword ptr [ebp-4],ecx
40: }
00401176 jmp pmemcpy+5Ah (0040114a)
41: }
00401178 pop edi
/*以下都为堆栈平衡*/
00401179 pop esi
0040117A pop ebx
0040117B add esp,48h
0040117E cmp ebp,esp
00401180 call __chkesp (00401230)
00401185 mov esp,ebp
00401187 pop ebp
00401188 ret
分享到:
相关推荐
C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言库函数速查手册C语言...
C语言库函数 C语言库函数 C语言库函数 C语言库函数
C语言中的库函数C语言中的库函数C语言中的库函数C语言中的库函数C语言中的库函数
C语言库函数手册,包含了大部分C语言库函数说明
C语言库函数 C语言库函数 C语言库函数
C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程 C语言库函数示例教程
C语言库函数大全 C语言库函数大全 C语言库函数大全
·C语言库函数速查 ·C语言库函数速查 ·C语言库函数速查 ·C语言库函数速查 ·C语言库函数速查 ·C语言库函数速查 ·C语言库函数速查
C语言库函数手册(20210926024352).pdf
C语言库函数.pdf 提供全部常用c语言库函数
C语言库函数 C语言库函数大全 C语言库函数 C语言库函数
C语言库函数大全 C语言库函数大全 C语言库函数大全 C语言库函数大全 C语言库函数大全 C语言库函数大全
C语言库函数:按各个字母开头的库函数都分开了的
C语言库函数及其示例,用于初学者学习C语言和掌握库函数
C语言库函数源代码。希望可以帮助到大家。
C语言库函数罗列。 提供了函数的原型,并有相关实例,可供查询,或学习使用方便的C语言库函数。