DLL中调用约定和名称修饰(二)

来源:互联网 发布:数控刀具网络销售 编辑:程序博客网 时间:2024/06/03 22:44

4、thiscall

thiscall调用约定是C++中的非静态类成员函数的默认调用约定。thiscall只能被编译器使用,没有相应的关键字,因此不能被程序员指定。采用thiscall约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,只是另外通过ECX寄存器传送一个额外的参数:this指针。

这次的例子中将定义一个类,并在类中定义一个成员函数,代码如下:

class CSum

{

public:

int Add(int a, int b)

{

return (a + b);

}

};

void main()

{

CSum sum;

sum.Add(1, 2);

}

函数调用部分汇编代码:

;CSum sum;

;sum.Add(1, 2);

push 2 ;参数从右到左入栈,先压入2

push 1 ;压入1

lea ecx,[ebp-4] ;ecx存放了this指针

call @ILT+5(CSum::Add) (0040100a) ;调用函数实现

函数实现部分汇编代码:

;int Add(int a, int b)

push ebp

mov ebp,esp

sub esp,44h ;多用了一个4bytes的空间用于存放this指针

push ebx

push esi

push edi

push ecx

lea edi,[ebp-44h]

mov ecx,11h

mov eax,0CCCCCCCCh

rep stos dword ptr [edi]

pop ecx

mov dword ptr [ebp-4],ecx

;return (a + b);

mov eax,dword ptr [ebp+8]

add eax,dword ptr [ebp+0Ch]

pop edi

pop esi

pop ebx

mov esp,ebp

pop ebp

ret 8 ;清栈

5、naked属性

采用上面所述的四种调用约定的函数在进入函数时,编译器会产生代码来保存ESI、EDI、EBX、EBP寄存器中的值,退出函数时则产生代码恢复这些寄存器的内容。对于定义了naked属性的函数,编译器不会自动产生这样的代码,需要你手工使用内嵌汇编来控制函数实现中的堆栈管理。由于naked属性并不是类型修饰符,故必须和__declspec共同使用。下面的这段代码定义了一个使用了naked属性的函数及其实现:

__declspec ( naked ) func()

{

int i;

int j;

_asm

{

push ebp

mov ebp, esp

sub esp, __LOCAL_SIZE

}

_asm

{

mov esp, ebp

pop ebp

ret

}

}

naked属性与本节关系不大,具体请参考MSDN。

6、WINAPI

还有一个值得一提的是WINAPI宏,它可以被翻译成适当的调用约定以供函数使用。该宏定义于windef.h之中。下面是在windef.h中的部分内容:

#define CDECL _cdecl

#define WINAPI CDECL

#define CALLBACK __stdcall

#define WINAPI __stdcall

#define APIENTRY WINAPI

由此可见,WINAPI、CALLBACK、APIENTRY等宏的作用。

2.名称修饰(Name Decoration

C或C++函数在内部(编译和链接)通过修饰名(Decoration Name)识别。函数的修饰名是编译器在编译函数定义或者原型时生成的字符串。编译器在创建.obj文件时对函数名称进行修饰。有些情况下使用函数的修饰名是必要的,如在模块定义文件里头指定输出C++重载函数、构造函数、析构函数,又如在汇编代码里调用C或C++函数等。

在VC++中,函数修饰名由编译类型(C或C++)、函数名、类名、调用约定、返回类型、参数等多种因素共同决定。下面分C编译、C++编译(非类成员函数)和C++类及其成员函数编译三种情况说明:

1、C编译时函数名称修饰

当函数使用__cdecl调用约定时,编译器仅在原函数名前加上一个下划线前缀,格式为_functionname。例如:函数int __cdecl Add(int a, int b),输出后为:_Add。

当函数使用__stdcall调用约定时,编译器在原函数名前加上一个下划线前缀,后面加上一个@符号和函数参数的字节数,格式为_functionname@number。例如:函数int __stdcall Add(int a, int b),输出后为:_Add@8。

当函数是用__fastcall调用约定时,编译器在原函数名前加上一个@符号,后面是加一个@符号和函数参数的字节数,格式为@functionname@number。例如:函数int __fastcall Add(int a, int b),输出后为:@Add@8。

以上改变均不会改变原函数名中的字符大小写。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2岁宝宝突然说话结巴怎么办 2岁宝宝突然结巴怎么办 幼儿舌头起泡牙龈出血怎么办 小孩长得太快怎么办 脑出血压着神经不会说话怎么办 四岁宝宝说话有点口吃怎么办 三岁宝宝有点口吃怎么办 3岁宝宝有点口吃怎么办 三岁宝宝说话有点口吃怎么办 六岁说话重复第一个字怎么办 宝贝烧到39.5度怎么办 宝贝39度不退烧怎么办 两岁多小儿突然变得口吃怎么办 百度两周岁宝宝口吃怎么办 2岁宝宝偶尔结巴怎么办 两岁宝宝说话磕巴怎么办 宝宝两岁结巴了怎么办 人多说话就紧张怎么办 小孩拉尿不叫人怎么办 2岁宝宝说话有点结巴怎么办 两岁半的宝宝说话结巴怎么办 2个月宝宝怕洗澡怎么办 2岁宝宝不喜欢喝奶粉怎么办 宝宝断奶不喜欢喝奶粉怎么办 宝宝不喜欢奶粉的味道怎么办 四个月宝宝不喜欢吃奶粉怎么办 四岁宝宝有口臭怎么办 4个月宝宝口臭怎么办 2岁宝宝有口臭是怎么办 两岁宝宝有口气怎么办 2岁宝宝口气重是什么原因怎么办 两岁宝宝口气重怎么办 两岁宝宝有口臭怎么办 两岁身高不达标怎么办 两岁宝宝82厘米怎么办 2岁幼儿说话结巴怎么办 2岁的宝宝结巴怎么办 2岁半宝宝口吃怎么办 2周岁宝宝不说话怎么办 三周岁宝宝不说话怎么办 2周岁宝宝突然说话结巴怎么办