通常编译器编译一个引用字符串的指令是使用指针来实现的.
字符”/0”表示字符转的结尾(这是C语言,Delphi是在字符串起始地址前添加了一个表示字符串实际长度的数值标值)
char *a={“AAAA”};
在内存中*a实际存放的数据是 41H 41H 41H 41H 00H
- int main()
- {
- char *a={"AAAA"};
- char *b={"BBBB"};
- printf("%s%s/n",a,b);
- return 0;
- }
反汇编代码如下:
- int main()
- {
- 012413A0 push ebp ;保护ebp的值
- 012413A1 mov ebp,esp ;ebp指向当前堆栈指针
- 012413A3 sub esp,0D8h ;为局部变量预留D8H的空间
- 012413A9 push ebx ;保护ebx寄存器的值
- 012413AA push esi
- 012413AB push edi
- 012413AC lea edi,[ebp-0D8h] ;edi指向局部变量缓冲区
- 012413B2 mov ecx,36h
- 012413B7 mov eax,0CCCCCCCCh
- 012413BC rep stos dword ptr es:[edi] ;循环复制数据到局部变量缓冲区,全部写入0CCCCCCCCh指令,即int 3指令的机器码。因为局部变量不会被执行,如果执行了程序就会出错,所以这时在这里发生中断。这个是VC编译的Debug版本特有的操作。
- char *a={"AAAA"};
- 012413BE mov dword ptr [a],offset string "AAAA" (124574Ch) ;字符串的地址存放在a中
- char *b={"BBBB"};
- 012413C5 mov dword ptr [b],offset string "BBBB" (1245744h) ;字符串的地址存放在b中
- printf("%s%s/n",a,b);
- 012413CC mov esi,esp ;esi指向当前堆栈指针
- 012413CE mov eax,dword ptr [b] ;字符串”BBBB”的指针存放到eax中
- 012413D1 push eax ;按照Cdecl调用约定,函数参数从右往左压入栈
- 012413D2 mov ecx,dword ptr [a] ;字符串”AAAA”的指针存放到ecx中
- 012413D5 push ecx ;ecx入栈
- 012413D6 push offset string "%s%s/n" (124573Ch) ;字符串” "%s%s/n”d的地址入栈
- 012413DB call dword ptr [__imp__printf (12482BCh)] ;调用printf函数
- 012413E1 add esp,0Ch ;调用者清理堆栈,之前压入了3个4字节的参数,所以现在要从堆栈弹出3*4=0Ch字节
- 012413E4 cmp esi,esp ;比较esi是否等于esp
- 012413E6 call @ILT+310(__RTC_CheckEsp) (124113Bh) ;调用_CheckEsp检测esp是否恢复正常
- return 0;
- 012413EB xor eax,eax ;eax清0
- }
- 012413ED pop edi ;恢复edi
- 012413EE pop esi
- 012413EF pop ebx
- 012413F0 add esp,0D8h ;清理堆栈
- 012413F6 cmp ebp,esp ;比较ebp是否等于esp
- 012413F8 call @ILT+310(__RTC_CheckEsp) (124113Bh)
- 012413FD mov esp,ebp ;恢复esp
- 012413FF pop ebp ;恢复ebp
- 01241400 ret ;函数返回
|