设为首页 加入收藏

TOP

C语言函数调用栈(二)(二)
2015-01-22 21:27:12 来源: 作者: 【 】 浏览:120
Tags:语言 函数 调用
2 ? ? ;mov DestRegister, SrcImmediate(Intel) vs. movl $SrcImmediate, %DestRegister(AT&T)
3 ? ? __asm mov eax, a
4 ? ? __asm add eax, b
5 ? ? __asm ret 8
6 }
? ? ?注意,__declspec是微软关键字,其他系统上可能没有。?
?
? ? ?6. pascal调用约定
?
? ? ?Pascal语言调用约定,参数按照从左至右的顺序入栈。Pascal语言只支持固定参数的函数,参数的类型和数量完全可知,故由被调函数自身清理堆栈。pascal调用约定输出的函数名称无任何修饰且全部大写。
?
? ? ?Win3.X(16位)时支持真正的pascal调用约定;而Win9.X(32位)以后pascal约定由stdcall约定代替(以C约定压栈以Pascal约定清栈)。
?
?
?
? ? ?上述调用约定的主要特点如下表所示:
?
调用方式
?
stdcall(Win32)
?
cdecl
?
fastcall
?
thiscall(C++)
?
naked call
?
参数压栈顺序
?
从右至左
?
从右至左
?
从右至左,Arg1在ecx,Arg2在edx
?
从右至左,this指针在ecx
?
自定义
?
参数位置
?
?
?
栈 + 寄存器
?
栈,寄存器ecx
?
自定义
?
负责清栈的函数
?
被调函数
?
主调函数
?
被调函数
?
被调函数
?
自定义
?
支持可变参数
?
?
?
?
?
自定义
?
函数名字格式
?
_name@number
?
_name
?
@name@number
?
?
?
自定义
?
参数表开始标识
?
"@@YG"
?
"@@YA"
?
"@@YI"
?
?
?
自定义
?
注:C++因支撑函数重载、命名空间和成员函数等语法特征,采用更为复杂的名字修饰策略。
?
C++函数修饰名以"?"开始,后面紧跟函数名、参数表开始标识和按照类型代号拼出的返回值参数表。
?
例如,函数int Function(char *var1,unsigned long)对应的stdcall修饰名为"?Function@@YGHPADK@Z"。
?
? ? ?Windows下可直接在函数声明前添加关键字__stdcall、__cdecl或__fastcall等标识确定函数的调用方式,如int __stdcall func()。Linux下可借用函数attribute 机制,如int __attribute__((__stdcall__)) func()。
?
? ? ?代码示例如下:
?
?1 int __attribute__((__cdecl__)) CalleeFunc(int i, int j, int k){
?2 // int __attribute__((__stdcall__)) CalleeFunc(int i, int j, int k){
?3 //int __attribute__((__fastcall__)) CalleeFunc(int i, int j, int k){
?4 ? ? return i+j+k;
?5 }
?6 void CallerFunc(void){
?7 ? ? CalleeFunc(0x11, 0x22, 0x33);
?8 }
?9 int main(void){
10 ? ? CallerFunc();
11 ? ? return 0;
12 }
复制代码
? ? ?被调函数CalleeFunc分别声明为cdecl、stdcall和fastcall约定时,其汇编代码比较如下表所示:
?
?
?
cdecl
?
stdcall
?
fastcall
?
主调函数职责
?
sub ? $0xc,%esp
?
movl ?$0x33,0x8(%esp)
?
movl ?$0x22,0x4(%esp)
?
movl ?$0x11,(%esp)
?
call ? 8048354
?
sub ? $0xc,%esp
?
movl ?$0x33,0x8(%esp)
?
movl ?$0x22,0x4(%esp)
?
movl ?$0x11,(%esp)
?
call ? 8048354
?
sub ? $0xc,%esp
?
sub ? $0x4,%esp
?
movl ?$0x33,(%esp)
?
mov ?$0x22,%edx
?
mov ?$0x11,%ecx
?
call ? 8048354
?
sub ? $0x4,%esp
?
被调函数职责
?
?push %ebp
?
mov ?%esp,%ebp
?
mov ?0xc(%ebp),%eax
?
add ?0x8(%ebp),%eax
?
add ?0x10(%ebp),%eax
?
pop ?%ebp
?
ret
?
push ?%ebp
?
mov ?%esp,%ebp
?
mov ?0xc(%ebp),%eax
?
add ? 0x8(%ebp),%eax
?
add ? 0x10(%ebp),%eax
?
pop ? %ebp
?
ret ? ?$0xc?
?
//执行ret指令并清理参数占用的堆栈(栈顶指针上移参数个数*4=12个字节,以释放压栈的参数)
?
push ?%ebp
?
mov ?%esp,%ebp
?
sub ? $0x8,%esp
?
mov ?%ecx,0xfffffffc(%ebp)
?
mov ?%edx,0xfffffff8(%ebp)
?
mov ?0xfffffff8(%ebp),%eax
?
add ? 0xfffffffc(%ebp),%eax
?
add ? 0x8(%ebp),%eax
?
leave
?
ret ? ?$0x4
?
//ret <压栈参数字节数>。若参数不超过两个,则ret指令不带立即数,因为无参数被压栈
?
?
?
5.2 调用约定影响
? ? ?当函数导出被其他程序员所使用(如库函数)时,该函数应遵循主要的调用约定,以便于程序员使用。若函数仅供内部使用,则其调用约定可只被使用该函数的程序所了解。
?
? ? ?在多语言混合 编程(包括A语言中使用B语言开发的第三方库)时,若函数的原型声明和函数体定义不一致或调用函数时声明了不同的函数约定,将可能导致严重问
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言编程积累2 下一篇C 语言的若干问题(持续更新中)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: