哈工大汇编大作业_第1页
哈工大汇编大作业_第2页
哈工大汇编大作业_第3页
哈工大汇编大作业_第4页
哈工大汇编大作业_第5页
已阅读5页,还剩51页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论