编程达人吧 关注:16贴子:35
  • 0回复贴,共1

3.1 C的汇编表示

只看楼主收藏回复

本节主要内容:
1. 观察内存变化
2. 汇编与C的联系
老唐语录:
1>在我们之前的代码里总是出现 int main(),现在在main函数的上方写代码。
__declspec(naked) int abc(int a,int b)
{
push ebx
push esi
push edi
pop edi
pop esi
pop ebx
ret
}
在int main()中添加
int r;
r=abc(2,3);
printf ("%d\n",r);
在r=abc(2,3);处下断点然后按F5,再按F11单步观察指令运行。
如果看懂每条指令的话,将每条指令改过的内存单元的编号记下来,写在纸上。
比如表3-1:
表3-1:内存地址书写格式
内存编号 内容
0x12ff2c 0x00000003
0x12ff28 0x00000002
0x12ff24 0x00401081
…… ……
内存编号可以从小到大,也可以从大到小排列,每4个字节为一个单位,没有被改过的内存内容不用写,只记下被修改过的内容。
2>现在修改__declspec(naked) int abc(int a,int b)里面的内容如下:
push ebx
push esi
push edi
//在此处添加三条语句
mov eax,[esp+0x10]
mov ecx,[esp+0x14]
add eax,ecx
然后单步调试并观察变化。为什么最终打印的结果是5,并将修改的内存画在纸上。
3>修改__declspec(naked) int abc(int a,int b)大括号里面的内容如下:
push ebp
mov ebp,esp
sub esp,4
push ebx
push esi
push edi
mov eax,[ebp+8]
add eax,[ebp+0xc]
mov [ebp-4],eax
pop edi
pop esi
pop ebx
mov eax,[ebp-4]
mov esp,ebp
pop ebp
ret
将修改的内存画在纸上。
修改abc(2,3)为其他整数比如,abc(10,2),观察结果变化。
问题:从r=abc(2,3)开始到printf指令之前共有几条指令改变了内存单元?
回答:共九个。
4>修改__declspec(naked) int abc(int a,int b)大括号里面的内容如下:
push ebp
mov ebp,esp
sub esp,0x44
push ebx
push esi
push edi
mov eax,0xcccccccc
mov ecx,0x11
lea edi ,[esp+0xc]
rep stosd
mov eax,[ebp+8]
add eax,[ebp+0xc]
mov [ebp-4],eax
pop edi
pop esi
pop ebx
mov eax,[ebp-4]
mov esp,ebp
pop ebp
ret
将修改的内存画在纸上。
现在在main()上面写下如下内容:
int abc(int a,int b,int c)
/*回车的地方都可以用空格代替,空格的地方可以用回车代替。也就是说,int a,int b,int c写在一行和写在三行是一回事。*/
{
int r;//每一句以分号结尾
r=a+b+c;
return r;
}
打比方,内存相当于算盘,但是算盘太多了,你根本就搞不清楚,给个地址,不好记,所以说,给每一个算盘取一个名字,比如:int a,int b,int c,int r,无论你取什么名字,都会分配给你四个字节的内存,然后在这个算盘上赋值,赋值很简单。我们称a,b,c为变量,也可以称为内存单元,赋值格式如下:
a = 2 ;
变量(内存单元) 等于 一个数,也可以是任意表达式 分号
不需要看C,看汇编如何显示。
圆括号和大括号里面定义的变量都可以赋值和使用,也可以不使用。
课后理解:
当在对一个数进行运算前,需要先规定其宽度,在C语言中我们称之为申明。
申明语句格式如下:
数据类型 变量名;
其中数据类型即数据宽度,C语言定义了以下几种数据类型:
int:32位
short:16位
char:8位
注:C语言除了十六进制数外,其他语句都区分大小写,这一点区别于汇编。
变量名也有要求:第一个字符必须是字母或下划线。可供使用的有小写字母、大写字母、数字和下划线。
我们现在用实例来说明一个完整的C程序:
使用VC6打开并创建一个控制台的HelloWorld程序,VC6自动为我们生成代码如下:
#include <stdio.h>
int main(void)/*程序入口*/
{
int num;/*申明一个名为num的变量*/
num = 1;/*赋值语句:num值为1*/
printf("Hello World!\n");/*调用一个库函数*/
return 0;/*返回*/
}
解析:
1〉首先我们要了解的是函数入口,即我们的程序从哪里开始运行:main函数。注意一个新名词:函数。函数的英文名是function,它的原意是功能、作用,所以“main函数”又可以译为“主功能”。
2〉那我们第一条执行的指令是:int num;申明语句,该条语句给了我们三条信息:该变量名字是num;宽度是32位;C语言的每一条语句后都要以”;”结尾。
3〉第二条语句:num = 1;给该变量赋1。既然num是变量,那么它的值可以再次被修改,这个留给大家测试。
4〉使用(专业术语是调用)一个printf函数,printf译为打印,所以我们可以说调用一个打印功能。
5〉return 0;返回0。该功能完成后,返回上一级。类似于我们去一个机关办事,办完事后,要从该机关出来才能去做下一件事。
课后疑问:
__declspec(naked)代表什么?
回答:代表裸函数,不要编译器帮我们构造函数框架,用户自己构造。
课后总结:
申明变量(比如int a)就是给内存取名。
课后练习:
抄写汇编函数框架。


1楼2016-06-10 15:57回复