版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
c、C++的秘密
哈工大信安一班
1150810613李秋豪
注:任何人可以自由的复制、修改、分发本文(GFDL)。但如果您的版本中包含本文
第一部分的“运算":1.在用于非商业、非盈利、非广告性目的时需注明作者及出处
“百度百科"。2.在用于商业、盈利、广告性目的时需征得作者同意,并注明作者姓
名、授权范围及出处"百度百科"。GMT+82016-12-1110:26
目录
语言元素的介绍
1,各数据类型
2.指针与地址
3.宏
4.运算
5.函数/子程序
二.各元素的对照
三.深入分析C/C++的实现
1.Switch
2.for循环
3.全局变量、局部变量
4.this指针及类成员函数
5.函数调用
6.参数传递
7.函数重载
四•指针/引用类型函数参数的底层实现
五•C与汇编的优缺点/适应场合
六.其他收获
一.语言元素的介绍
注:C(C99)ASM(MASM32)
环境:windows7_32+codeblocksl6.01+MinGW
各数据类型:
short
long
longlong
float
double
long
double
C99数据类
型
C中各类型占用字节数:
Sizeofintis:4
Sizeofunsignedintis:4
Sizeofshortis:2
Sizeofunsignedshortis:2
Sizeo£longis:4------------------------------------------------
Sizeofunsignedlongis:4
Sizeoflonglongis:8
Sizeofunsignedlonglongis:8
Sizeofcharis:1
Sizeofsignedcharis:1
Sizeofunsignedcharis:1
Sizeoffloatis:4
Sizeofdoubleis:8
Sizeoflongdoubleis:12
Processreturned0<0x0)executiontine:0.096s
»anykeytocontinue.
源代码1-1
#include<stdio.h>
intmain()
(
printf("Sizeofintis:%d\n",sizeof(int));
printf("Sizeofunsignedintis:%d\n",sizeof(unsignedint));
printf("Sizeofshortis:%d\n",sizeof(short));
printf("Sizeofunsignedshortis:%d\n",sizeof(unsignedshort));
printf("Sizeoflongis:%d\n",sizeof(long));
printf("Sizeofunsignedlongis:%d\n",sizeof(unsignedlong));
printf("Sizeoflonglongis:%d\n",sizeof(longlong));
printf("Sizeofunsignedlonglongis:%d\n",sizeof(unsignedlonglong));
printf("Sizeofcharis:%d\n",sizeof(char));
printf("Sizeofsignedcharis:%d\n",sizeof(signedchar));
printf("Sizeofunsignedcharis:%d\n",sizeof(unsignedchar));
printf("Sizeoffloatis:%d\n",sizeof(float));
printf("Sizeofdoubleis:%d\n",sizeof(double));
printf("Sizeoflongdoubleis:%d\n",sizeof(longdouble));
return0;
)
指针:(具体分析见后)
在32位平台里,指针本身占据了4个字节的长度。
结构体和联合体:
结构体占用内存的大小为该结构体内部元素之和,但由于存在内存对齐问题:在数据
成员完成各自对齐以后,struct或者union本身也要进行对齐,对齐将按照#pragma
pack指定的数值和struct或者union中最大数据成员长度中比较小的那个进行(注:
每个特定平台上的编译器都有自己的默认"对齐系数"。通过预编译命令#pragma
pack(k),k=l,2,4,8,16来改变这个系数,其中k就是需要指定的"对齐系数";也可
以使用#pragmapack。取消自定义字节对齐方式。)
测试代码:1-2
#include<stdio.h>
structTest
chara;
intb;
intc;
chard;
);
intmain()
(
structTeststructTest;
printf("&a=%p\n",&structTest.a);
printf("&b=%p\n",&structTest.b);
printf("&c=%p\n",&structTest.c);
printf("&d=%p\n",&structTest.d);
printf("sizeof(Test)=%d\n",sizeof(structTest));
return0;
)
结果为:
&a=00C7FA44
&b=00C7FA48
&c=00C7FA4C
&d=00C7FA50
sizeof(Test)=16
结构体Test的成员变量b占用字节数为4bytes,所以只能存储在4的整数倍的位置
上,由于a只占用1Y字节,而a的地址00C7FA44和b的地址00C7FA48之间
相差4bytes,这就说明,a其实也占用了4个字节,这样才能保证b的起始地址是4
的整数倍。
引用分析:
根据《C++primer5th》(我眼中的权威。。。哈哈),引用并非对象,但一定要深
究的话。。。也只能从汇编上来分析了,贴代码>3:(vs2010)
#include"stdafx.h"
int_tmain(intargc,_TCHAR*argv[])
{
inta=1;
int&b=a;
b=2;
return0;
)
inta=1;
G0FF139Emovdwordptr[a],l
int&b"a;
O|seFFl3A5leaeax,[a]
^GFF13A8movdwordptr[b],eax
b=2;
GOFF13ABmoveax,dwordptr[b]
G0FF13AEmovdwordptr[eax],2
return0;
▼Dx
EAX-0099FBA0EBX=0089(1000ECX«00000000EDX-00000001ESI-00FF106E
EDI-0099FBA8EIP-00FF13A8ESP-0099FAC4EBP-0099FBA8EFL-00000202
0999FB94=CCCCCCCC
▼t3X
ieut:0x0Q99FBA0
I」1ei0000eecccccccc....??>?
0X9099FBA8f8fb99005f19ff90
0X©099rBB00100000058122031….X..
0X9099F8B8f812200127fa8bec?..'???
8xe099F8C06e10ff006e10ffBOn...n...
0X0099F8C800ceb90e0000a03f
0X0099FBD0f8fb990000000030???....
二一,Q二二二二一:'CCCCC—CCCCCC6c、
可以看出,在汇编的层面,引用使用"指针"的概念实现的。所以其占用的空间和指
针一样。
ASM:
在汇编中,数据类型只是按照占用内存大小进行排序,如果不添加说明,处理
时不经过检查。
byte:8位无符
号整数
word:16位无
符号整数
dword:32位无
符号整数
qword:64位整
数
ASM数据类型
实数
源代码>4
.data
VIbyte?
V2sbyte?
V3word?
V4sword?
V5dword?
V6sword?
C(指针):
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。
L指针的类型。
⑴int*ptr;〃指针的类型是int*
(2)char*ptr;//指针的类型是char*
⑶int**ptr;〃指针的类型是int**
(4)int(*ptr)[3];〃指针的类型是int(*)[3]
⑸int*(*ptr)[4];〃指针的类型是int*(*)[4]
2.指针所指向的类型。
当通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译
器将把那片内存区里的内容当做什么类型的数据来看待。
从语法上看,只须把指针声明语句中的指针名字和名字左边的指针声明符
*去掉,剩下的就是指针所指向的类型。例如:
(Dint*ptr;〃指针所指向的类型是int
(2)char*ptr;〃指针所指向的的类型是char
⑶int**ptr;〃指针所指向的的类型是int*
(4)int(*ptr)[3];〃指针所指向的的类型是int()[3]
⑸int*(*ptr)[4];〃指针所指向的的类型是int*()[4]
例子(C++与汇编):源代码1-5
C++:
#include<iostream>
usingnamespacestd;
intmain()
(
int*p=0;
inta{0};
p=&a;
cout<<p<<endl;
cout<<*p<<endl;
return0;
)
ASM:
;int*p=0;
movdwordptr[p],0
p=&a;
leaeax,[a]
movdwordptr[p],eax
宏:
在c中,宏是一种预处理指令,它提供了一种机制,可以用来替换源代码中的
字符串,宏是用"#define"语句定义的,下面是一个宏定义的例子:
#defineN"100"
上例中所定义的这种形式的宏通常被称为标识符。在上例中,标识符N即代表
字符串"100”——在编译预处理时,源代码中的每个N标识符都将被字符串
“100"替换掉。
在汇编中,宏定义是用一组伪操作来实现的。其格式是:
macro_nameMACRO[dumny_parameter_list]
...(宏定义体)
ENDM
其中MACRO和ENDM是一对伪操作.这对伪操作之间是宏定义体一是一组独
立功能的程序代码宏指令名(macro_name)给出该宏定义的名称,调用时就使用
宏指令名来调用该宏定义.其中哑元表(dumny_parameter_list)给出了该宏定义
中所用到的形式参数(或称虚参),每个哑元之间用逗号隔开.
经宏定义后的宏指令就可以在源程序中调用.这种对宏指令的调用称为宏调用,
宏调用的格式是:
macroname[actualparameterlist]
实元表(actual_parameter_list)中的每一项为实元,相互之间用逗号隔开。
运算:(来自百度百科)
C:
基本表达式1级
基本表达式(Primaryexpressions),主要是用于运算符之间,做为运算数。
标识,常量,字符串文字量,优先级提升表达式最优先执行。
优先级提升表达式是指圆括号包围的表达式,如"(expression)”
后缀表达式2极
postfix-expression[expression],数组下标运算。
postfix-expression(argument-expression-list),函数调用,括号内的参数
可选。
postfix-expression.identifier,成员访问,
postfix-expression->identifier,成员访问,-〉号之前应为指针。
postfix-expression++,后缀自增
postfix-expression—,后缀自减
(type-name){initializer-list}
(type-name){initializer-list,)复合初始化
单目/一元运算3级
++unary-expression前缀自增
—unary-expression前缀自减
unary-operatorcast-expression单目转型表式式,包括取地址&,提领*
正号+,负号-位反~逻辑否!。
sizeofunary-expression求类型长度,对表达式求类型长度
sizeof(type-name)求类型长度
强制类型表达式4级
(type-name)cast-expression,强制表达式成为type-name指定的类型。
乘法表达式5级
乘法运算符;"/"除法运算符;"%"取余运算符。
加法运算符6级
"+"加法运算符;"-"减法运算符。
移位运算符7级
<<左移运算符;>>右移运算符。
关系运算符8级
<、<=、>、>=关系运算符。
相等运算符9级
"=="等于运算符;"上"不等于运算符。
位与运算符10级
"&"按位与运算符
位异或运算符11级
按位异或运算符(
"A"BitwiseexclusiveORoperator)o
位或运算符12级
按位或运算符(
BitwiseinclusiveORoperator)0
逻辑与运算符13级
"&&"逻辑与运算符。
逻辑或运算符14级
"||"逻辑或运算符。
三元条件运算符15级
?:条件运算符。
赋值运算符16级
=、+=、-=、*=、/=、%=、&=、人=、|=、<<=、>>=赋值运算符。
逗号运算符17级
:"逗号运算符。
[pre]C语言中,逗号(,)也可以是运算符,称为逗号运算符(Comma
)逗号运算符可以把两个以上(包含两个)的表达式连接成一个表
Operatoro
达式,称为逗号表达式。其一般形式为:
子表达式1,子表达式2,…,子表达式n
例如:
a+b,c=b,C++
逗号运算符的优先级是所有运算符中级别最低的,通常配合for循环使用。
逗号表达式最右边的子表达式的值即为逗号表达式的值。上例中,C++的值
(c自增之前的值)即为该表达式的值。
逗号运算符保证左边的子表达式运算结束后才进行右边的子表达式的运算。
也就是说,逗号运算符是一个序列点,其左边所有副作用都结束后,才对其右
边的子表达式进行运算。因此,上例中,C得到b的值后,才进行自增运算。
ASM:
算术运算指令
ADD加法.
ADC带进位加法.
INC力口1.
AAA加法的ASCH码调整
DAA加法的十进制调整.
SUB减法.
SBB带借位减法.
DEC减1.
NEC求反(以0减之).
CMP比较.(两操作数作减法,仅修改标志位,不回送结果).
AAS减法的ASCII码调整.
DAS减法的十进制调整.
MUL无符号乘法.
IMUL整数乘法.
以上两条,结果回送AH和AL(字节运算),或DX和AX(字运算),
AAM乘法的ASCII码调整.
DIV无符号除法.
IDIV整数除法.
以上两条,结果回送:
商回送AL,余数回送AH,(字节运算);
或商回送AX,余数回送DX,(字运算).
AAD除法的ASCII码调整.
CBW字节转换为字.(把AL中字节的符号扩展到AH中去)
CWD字转换为双字.(把AX中的字的符号扩展到DX中去)
CWDE字转换为双字.(把AX中的字符号扩展到EAX中去)
CDQ双字扩展.(把EAX中的字的符号扩展到EDX中去)
逻辑运算指令
AND与运算.
OR或运算.
XOR异或运算.
NOT取反.
TEST测试.(两操作数作与运算,仅修改标志位,不回送结果).
SHL逻辑左移.
SAL算术左移(=SHL)
SHR逻辑右移.
SAR算术右移.仁SHR)
ROL循环左移.
ROR循环右移.
RCL通过进位的循环左移.
RCR通过进位的循环右移.
以上八种移位指令,其移位次数可达255次.
移位一次时,可直接用操作码.如SHLAX,1.
移位〉1次时,则由寄存器CL给出移位次数.
如MOVCL,04
SHLAX,CL
函物子影:
C:
L函数的定义:
返回类型函数名(参数列表){
函数体;
)
如:
1)带返回值的定义
intsuml(intm){
inti,sum=0;
for(i=l;i<=m;i++)
sum=sum+i;
returnsum;
)
2)没有返回值
voidsum2(intm){
intI,sum=0;
for(i=l;i<=m;i++)
sum=sum+i;
s=sum;
)
2、函数的引用:
1)带返回值的引用
Intmain(){
intn,s;
s=sum(n);
printf("%d",s);
return0;
)
2)没有返回值的引用
Ints;
main(){
intn;
sum2(n);
printf(〃%d〃,s);
return0;
)
例子:源代码1-6
#include<conio.h>
#include<stdio.h>
ints;
intsuml(intm){
intizsum=0;
for(i=l;i<=m;i++)
sum=sum+i;
returnsum;
)
voidsum2(intm){
intizsum=0;
for(i=l;i<=m;i++)
sum=sum+i;
s=sum;
}
Intmain(){
intn,s;
scanf("%d",&n);
s=suml(n);
printf("suml(n)=%d\nn,s);
getchQ;
sum2(n);
printf("sum2(n)=%d",s);
return0;
)
3)定义函数的目的:将程序按功能分块,方便程序的使用、管理、阅读、和调试。
ASM:
汇编里的子程序是具有固定功能的程序段,并且有规定的格式。不同的计算机语言对
子程序格式的规定不同,汇编语言的子程序基本格式如下:
子程序名PROC类型
指令序列
子程序名ENDP
格式中的首尾两行表示一个子程序的开始和结束,都属于伪指令。"子程序名"是一
个标识符,是编程者给子程序起的名字。子程序名同时还代表子程序第一条指令所在
的逻辑地址,称为子程序的入口地址。"类型"只有NEAR和FAR两种,它将影响汇
编程序对子程序调用指令CALL和返回指令RET的翻译方式。被夹在子程序起止伪指
令之间的指令序列是完成子程序固定功能的程序段,通常指令序列的最后一条指令是
返回指令RET。
指令:CALL子程序名
功能:这是调用子程序的指令。根据被调用的子程序的类型不同,CALL指令的功能
分为两种情况:
(1)如果被调用的子程序是NEAR类型,则先把当前指令指针IP的值入栈,这会使
SP的值减2,然后把IP改成子程序的第1条指令的偏移地址。
(2)如果被调用的子程序是FAR类型,则先把当前CS寄存器的值入栈,再把IP入
栈,结果会使SP的值减4,然后把CS和IP改为子程序第1条指令的逻辑地址。
指令:RET
功能:这是子程序返回指令,必须写在子程序的指令序列之中。根据所在的子程序的
类型不同,RET指令的功能也分为两种情况:
(1)如果RET所在子程序是NEAR类型,则从堆栈中出栈一个字(当然,SP会加2),
送给以
(2)如果RET所在子程序是FAR类型,则先从堆栈中出栈一个字送到IP,再出栈一
个字送到栈顶指的值加
CS,SP4O
二.各元素的对照
方面/语言C/C++ASM
数据类型Int/char/bool...Byte/word/...
宏#defineMacro-ENDM
调用函数子程序
JS算算数/逻辑/库操作指令/库
r指针变量(各种地址(偏移/物
类型)理)
I/O输入输出函数中断(int21...)
三.深入分析C/C++的实现
1.switch语句
源代码3-1及其分析:(为简便,从3-2开始不再分析开始的入栈/现场保护/申
请局部变量空间和结束时的出栈/恢复语句)
C++:
//switch.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
int_tmain(intargc,_TCHAR*argv[])
(
inta=1;
switch(a)
(
case0:a=0;
break;
case1:a=1;
break;
default:break;
)
return0;
)
ASM:
11switch.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
int_tmain(intargc,_TCHAR*argv[])
009B17A0pushebp〃使用ebp作为基准,并在结束时恢复
009B17A1movebp,esp
009B17A3subesp,ODOh〃为局部变量生成空间
009B17A9pushebx
009B17AApushesi
009B17ABpushedi〃压栈,保护现场
009B17ACleaedi,[ebp-ODOh]〃将局部变量的开始地址保存到edi中
009B17B2movecx,34h〃设置循环变量
009B17B7moveax,OCCCCCCCCh〃初始化eax
009B17BCrepstosdwordptres:[edi]〃初始化申请的空间
〃像es中输入[ebp-ODOh](循环ecx次)
inta=1;
009B17BEmovdwordptr[a],l〃赋值语句
switch(a)
009B17C5moveax,dwordptr[a]
009B17C8movdwordptr[ebp-0D0h],eax
009B17CEcmpdwordptr[ebp-0D0h],0〃比较0与a的值
009B17D5jewmain+42h(9B17E2h)〃若相等,跳至a=0
009B17D7cmpdwordptr[ebp-ODOh],l〃比较1与a的值
009B17DEjewmain+4Bh(9B17EBh)〃若相等,跳至a二l
009B17E0jmpwmain+52h(9B17F2h)〃跳出
(
case0:a=0;
009B17E2movdwordptr[a],0〃执行操作,赋值a=0
break;
009B17E9jmpwmain+52h(9B17F2h)〃跳出;
case1:a=1;
009B17EBmovdwordptr[a],l〃执行操作,赋值a=l
break;
default:break;
)
return0;
009B17F2xoreax,eax
)
009B17F4popedi〃还原寄存器
009B17F5popesi
009B17F6popebx
009B17F7movesp,ebp
009B17F9popebp〃恢复ebp
009B17FAret〃结束,弹出返回地址
2.for循环
源代码3-2及其分析:
C++:
//for.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
int_tmain(intargc,_TCHAR*argv[])
(
inti;
inta=0;
for(i=0;i!=9;++i)
++a;
)
return0;
)
ASM:
//for.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
int_tmain(intargc,_TCHAR*argv[])
01121350pushebp
01121351movebp,esp
01121353subesp,0D8h
01121359pushebx
0112135Apushesi
0112135Bpushedi
0112135Cleaedi,[ebp-0D8h]
01121362movecx,36h
01121367moveax,OCCCCCCCCh
0112136Crepstosdwordptres:[edi]
inti;
inta=0;
0112136Emovdwordptr[a],0〃赋值语句,将赋值为0
for(i=0;i!=9;++i)
01121375movdwordptr[i],0〃赋值语句,将循环变量i设置为0
0112137Cjmpwmain+37h(1121387h)
〃跳至循环条件判断语句,将i与9进行匕蹄交
0112137Emoveax,dwordptr[i]
01121381addeax,l
01121384movdwordptr[i],eax
01121387cmpdwordptr[i],9
0112138Bjewmain+48h(1121398h)〃若达到循环边界,退出循环
++a;
0112138Dmoveax,dwordptr[a]/涛未达到边界,执行++a操作
01121390addeax,l
01121393movdwordptr[a],eax
1
01121396jmpwmain+2Eh(112137Eh)〃再次循环
return0;
01121398xoreax,eax
)
0112139Apopedi
0112139Bpopesi
0112139CPOPebx
0112139Dmovesp,ebp
0112139Fpopebp
011213A0ret
3.全局变量、局部变量
源代码3-3及其分析:
C++:
//globallocal.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
inta=1;
voidsum(intc,intd);
int_tmain(intargc,_TCHAR*argv[])
intb=2;
++b;
++a;
sum(a,b);
return0;
)
voidsum(intc,intd)
(
++c;
++d;
return;
)
ASM:
//globallocal.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
inta=1;
voidsum(intc,intd);
int_tmain(intargc,_TCHAR*argv[])
00C21380pushebp
00C21381movebp,esp
00C21383subesp,OCCh
00C21389pushebx
00C2138Apushesi
00C2138Bpushedi
00C2138Cleaedi,[ebp-OCCh]
00C21392movecx,33h
00C21397moveax,OCCCCCCCCh
00C2139Crepstosdwordptres:[edi]
intb=2;
00C2139Emovdwordptr[b],2〃赋值语句,将b赋值为2
++b;
00C213A5moveax,dwordptr[b]〃执行++b操作
00C213A8addeax,l
00C213ABmovdwordptr[b],eax
++a;
〃有一些奇怪,我没有看见为声明全局变量a的语句,但事实证明编译器的确为a在
内存中分配了一块空间,且此空间作用域为整个源文件
〃调用内存查看:证明0C27000h即为a的地址:
内存1▼口X
碘:|OxOOC27OOO⑻
0xa0C270000206000001000030.......
0xd0C2700801000000010000d9.......
0XO0C2/010010000ee01000090.......
0xeec270i800000000feffffff
0xd0C2702001000000ffffffff.......
0xO0C27028ffffffff00000030.......
0X60C27030893779a876c88657?7y?v??W
-Mir^A/WlAA
00C213AEmoveax,dwordptr[a(0C27000h)]〃执行++a操作
00C213B3addeax,l
00C213B6movdwordptr[a(0C27000h)],eax
sum(a,b);
00C213BBmoveax,dwordptr[b]
〃通过eax压栈达到value-pass
00C213BEpusheax
00C213BFmovecx,dwordptr[a(0C27000h)]
00C213C5pushecx
00C213C6callsum(0C211A9h)//调用sum函数
00C213CBaddesp,8〃清除堆栈
return0;
00C213CExoreax,eax
}
00C213D0popedi
00C213D1popesi
00C213D2popebx
00C213D3addesp,0CCh
00C213D9cmpebp,esp
00C213DBcall@ILT+305(_RTC_CheckEsp)(0C21136h)
〃调用eserror函数,估计是错误处理
00C213E0movesp,ebp
00C213E2popebp
00C213E3ret
voidsum(intc,intd)
00C21400pushebp
00C21401movebp,esp
00C21403subesp,OCOh
00C21409pushebx
00C2140Apushesi
00C2140Bpushedi
00C2140Cleaedi,[ebp-0C0h]
00C21412movecx,30h
00C21417moveax,OCCCCCCCCh
00C2141Crepstosdwordptres:[edi]
++C;
00C2141Emoveax,dwordptr[c]〃对局部变量执行加一操作
00C21421addeax,l
00C21424movdwordptr[c],eax
++d;
00C21427moveax,dwordptr[d]〃对局部变量执行加一操作
00C2142Aaddeax,l
00C2142Dmovdwordptr[d],eax
return;
)
00C21430popedi
00C21431popesi
00C21432popebx
00C21433movesp.ebp
00C21435popebp
00C21436ret
4.this指针及类成员函数
源代码3-4及其分析:
C++:
//this.cpp:
//
#include"stdafx.h"
#include<iostream>
intmain()
intdd;
structA
(
intbb;
intaa()
(
returnbb;
)
}cc;
cc.bb=1;
dd=cc.aa();
return0;
)
ASM:
//this.cpp
//
#include"stdafx.h"
#include<iostream>
intmain()
01071380pushebp
01071381movebp,esp
01071383subesp,0D8h
01071389pushebx
0107138Apushesi
0107138Bpushedi
0107138Cleaedi,[ebp-0D8h]
01071392movecx,36h
01071397moveax,OCCCCCCCCh
0107139Crepstosdwordptres:[edi]
}cc;
cc.bb=1;
0107139Emovdwordptr[cc],l〃向类成员赋值
dd=cc.aaQ;
010713A5leaecx,[cc]〃传参(地址)
010713A8call'main'::'2,::A::aa(1071410h)
010713ADmovdwordptr[dd],eax
〃从1071410子程序中返回成员值,并对局部变量dd赋值
return0;
010713B0xoreax,eax
)
010713B2pushedx
010713B3movecx,ebp
010713B5pusheax
010713B6leaedx,[(10713D8h)]
010713BCcall@ILT+120(®_RTC_CheckStackVars@8)(107107Dh)
010713C1popeax
010713C2popedx
010713C3popedi
010713C4popesi
010713C5popebx
010713C6addesp,0D8h
010713CCcmpebp,esp
010713CEcall@ILT+295(_RTC_CheckEsp)(107112Ch)
010713D3movesp,ebp
010713D5popebp
intdd;
structA
intbb;
intaa()
〃读取类成员的值
01071410pushebp
01071411movebp,esp
01071413subesp,0CCh
01071419pushebx
0107141Apushesi
0107141Bpushedi
0107141Cpushecx
0107141Dleaedi,[ebp-OCCh]
01071423movecx,33h
01071428moveax,OCCCCCCCCh
0107142Drepstosdwordptres:[edi]
0107142Fpopecx
01071430movdwordptr[ebp-8],ecx
returnbb;
01071433moveax,dwordptr[this]〃通过this指针进入类
01071436moveax,dwordptr[eax]〃读取类成员的值,通过eax返回
}
〃通过以上分析,在调用成员函数时,实际上是在替某个对象调用它。具体来说,成
员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。而这个this指
针是被请求调用该函数的对象地址所初始化的。形象的说,我在使用aa.cc()时,实际
上是在使用A::cc(&aa)。(虽然这么写是非法的。。。)
5.函数调用与参数传递
源代码3-5及其分析:
C++:
//function.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
intsum(intc,intd);
int_tmain(intargc,_TCHAR*argv[])
(
inta=1;
intb=2;
intc;
c=sum(a,b);
return0;
)
intsum(intc,intd)
returnc+d;
)
ASM:
//function.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
intsum(intc,intd);
int_tmain(intargc,_TCHAR*argv[])
003C1380pushebp
003C1381movebp,esp
003C1383subesp,OE4h
003C1389pushebx
003C138Apushesi
003C138Bpushedi
003C138Cleaedi,[ebp-OE4h]
003C1392movecx,39h
003C1397moveax,OCCCCCCCCh
003C139Crepstosdwordptres:[edi]
inta=1;
003C139Emovdwordptr[a],l〃局部变量赋值
intb=2;
003C13A5movdwordptr[b],2〃局部变量赋值
intc;
c=sum(a,b);
003C13ACmoveax,dwordptr[b]
003C13AFpusheax〃通过堆栈进行value-pass
内存1▼DX
10x01OFF9A4■d••
0X010FF98400007601335f0000
0X010FF98C0400000000007601
0X010FF994f497010173103c00
0X010FF99C73103c0002000000
|x010FF9A473103c0073103c00
0X010FF9AC0080e300CCcccccc
0X010FF9B4cccccccccccccccc
003C13B0movecxzdwordptr[a]
003C13B3pushecx〃通过堆栈进行value-pass
内存1▼□X
003C13B4callsum(3C1055h)
〃调用函数sum,并把下一跳语句的地址003cl3b9存入栈中
//eip中的值改变为sum函数的起始地址
003C13B9addesp,8
〃将esp回退至局部变量处
内存1▼□X
OO3C13BCmovdwordptr[c],eax
return0;
003C13BFxoreax,eax
}
003C13C1popedi
003C13C2popesi
003C13C3popebx
003C13C4addesp,0E4h
003C13CAcmpebp,esp
003C13CCcall@ILT+310(_RTC_CheckEsp)(3C113Bh)
003C13D1movesp,ebp
003C13D3popebp
003C13D4ret
intsum(intc,intd)
(
003C13F0pushebp
003C13F1movebp,esp
003C13F3subesp,0C0h
003C13F9pushebx
003C13FApushesi
003C13FBpushedi
003C13FCleaedi,[ebp-0C0h]
003C1402movecx,30h
003C1407moveax,OCCCCCCCCh
003C140Crepstosdwordptres:[edi]
returnc+d;
003C140Emoveax,dwordptr[c]
□x
EAX-eee000€2EBX-eoEsseeeECX«00000001EDX-eeeeeeeiESI«eescie73
EDI-01GFFA94EIP-003cle55ESP-010FF998EBP-010FFA94EFL-00000202
003C1411addeax,dwordptr[d]
〃进行相加操作,并通过eax返回
---------------------------------1
▼口X
EAX-00000003EBX-00E38000ECX-00000000EDX-00000001ESI-003cl073
EDI-010FF994EIP-063cl414ESP-010FF8C8EBP-O10FF994EFL-00000206
}
003C1414popedi
003C1415popesi
003C1416popebx
003C1417movesp.ebp
003C1419popebp
003C141Aret
〃经过以上分析,在调用函数时,先将下一条语句的地址保存到栈中,并改变eip,使
执行地址从调用的函数开始,这时可以通过寄存器进行传参。进入调用的函数后,在
返回时,eip重新变化为原来栈中保存的下一条语句的地址,可以通过寄存器返回返回
值。并将esp进行复位。
6.函数重载
源代码3-6及其分析:
C++:
//overloaded.cpp:定义控制台应用程序的入口点。
//
#include"stdafx.h"
voidA(intal)
(
--al;
return;
)
voidA(charbl)
++bl;
return;
)
int_tmain(intargc,_TCHAR*argv[])
(
inta=1;
charb='a';
A(a);
A(b);
return0;
)
ASM:
int_tmain(intargc,_TCHAR*argv[])
01151410pushebp
01151411movebp,esp
01151413subesp,0D8h
01151419pushebx
0115141Apushesi
0115141Bpushedi
0115141Cleaedi,[ebp-0D8h]
01151422movecx,36h
01151427moveax,OCCCCCCCCh
0115142Crepstosdwordptres:[edi]
inta=1;
0115142Emovdwordptr[a],l〃给局部变量赋值
charb='a';
01151435movbyteptr[b],61h//局部变量赋值
A(a);
01151439moveax,dwordptr[a]
0115143Cpusheax〃通过堆栈进行value-pass
0115143DcallA(11510F0h)
〃至于为什么会选择11510F0处的函数,请看后面的映像文件
01151442addesp,4〃将esp指向下一个局部变量
A(b);
01151445movzxeax,byteptr[b]
01151449pusheax〃通过堆栈进行value-pass
0115144AcallA(115110Eh)
0115144Faddesp,4〃清除堆栈
return0;
01151452xoreax,eax
voidA(intal)
t
01151390pushebp
01151391movebp,esp
01151393subesp,0C0h
01151399pushebx
0115139Apushesi
0115139Bpushedi
0115139Cleaedi,[ebp-0C0h]
011513A2movecx,30h
011513A7moveax,OCCCCCCCCh
011513ACrepstosdwordptres:[edi]
-al;
011513AEmoveax,dwordptr[al]〃为局部变量执行减一操作
011513B1subeax,l
011513B4movdwordptr[al],eax
return;
)
voidA(charbl)
011513D0pushebp
011513D1movebp,esp
011513D3subesp,0C0h
011513D9pushebx
011513DApushesi
011513DBpushedi
011513DCleaedi,[ebp-0C0h]
011513E2movecx,30h
011513E7moveax,OCCCCCCCCh
0115
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024至2030年中国幼儿园露天游乐设备市场运行格局及投资潜力研究报告
- 2024-2030年中国工业用埋弧焊剂市场专题研究及市场前景预测评估报告
- 2024至2030年中国卷式超滤膜元件行业销量预测及投资商机分析报告
- 2024-2030年中国5羟基异喹啉市场专题研究及市场前景预测评估报告
- 2025年高考数学一轮复习之统计
- 一次方程(组)(原卷版)-2024年中考数学真题
- 第三章 基本几何元素的投影(3-2)
- 浙江省某中学2023年中考英语模拟试卷(含答案)
- 人教版九年级数学下册相似《位似(第2课时)》示范教学设计
- 咨询服务合同
- 二年级语文下册 猜字谜(课堂PPT)
- 核心网设备安装工程质量控制点
- 推进创新券跨区域通用通兑的政策建议
- 新增旅游车可行性报告五篇范文
- 汪氏气数学物质连锁反应之十神取象
- 上市公司并购重组课件
- tf家族练习生招募报名表
- 多媒体展示系统施工组织设计方案
- 大医精诚原文及翻译
- 对高中生物课互动式教学方式的研究
- 日语简历模板
评论
0/150
提交评论