Microsoft函数调用约定

对于所有调用共有的约定:ebx、ebp、esi、edi都是calle-save,即由被调用的函数负责它们的保存(如果被调用函数用到了这些寄存器的话)

先看函数调用发生了什么:(win32下)
1、所有参数提升到4bytes的倍数
2、执行call指令
3、将ebx、ebp、esi、edi保存在栈上,这一步称为function prolog
4、将返回值放在eax中(返回int64放在edx:eax中,返回double放在浮点寄存器中。复杂的数据结构在caller的栈中分配空间,将首地址做为最后压栈的参数(我拿__cdecl试的),callee返回的时候将返回值放在这个指针指向的地址)
5、取出ebx、ebp、esi、edi,这一步称为function epilog
6、清空栈,保持堆栈平衡,这一步称为stack cleanup

具体的调用约定:
1、__cdecl
压栈顺序:从右至左
清栈:函数调用者负责清空,称为caller cleanup
名字修饰(name decoration):在函数名前加上下划线做前缀,比如_foo
注:c/c++函数的缺省调用约定

2、__stdcall
压栈顺序:从右至左
清栈:被调用函数负责清空,称为callee cleanup
名字修饰:在函数名前加上下划线做前缀,名字后用@加上函数参数大小做后缀,如_foo@8
注:WINAPI就是__stdcall的#define

3、__fastcall
压栈顺序:第一个参数放在ecx,第二个参数放在edx,其余从右至左
清栈:callee cleanup
名字修饰:在函数名前加上@做前缀,名字后用@加上函数参数大小做后缀,如@foo@8
注:名字叫fast实际就不一定了……

4、thiscall
压栈顺序:this指针(cpp非静态成员函数特有)放在ecx,其余从右至左
清栈:callee cleanup
注:cpp非静态成员函数默认的调用约定

5、naked
压栈顺序:从右至左
清栈:caller cleanup
注:VxDs用的调用约定,将__declspec(naked)写在函数定义处(注意,不是声明)

这篇文章把naked作为calling convention: http://www.cs.cornell.edu/courses/cs412/2001sp/resources/microsoft-calling-conventions.htm

但naked应该算不上调用约定了,只是单纯地将c/c++代码翻译成asm,连esp、ebp之间的保存、mov都没有就直接拿ebp来寻址了,函数结束后也不管ret,太naked了!

补充:c允许可变参数(例如printf),为了方便地使用这些函数,所以__cdecl要
1、从右至左压栈(这样才能知道第一个参数在堆栈中的地址)
2、caller cleanup(因为只有caller才知道这次调用push了多少参数

函数调用约定的历史——16位的世界:

对所有的调用约定:
1、用dx:ax或ax保存返回值
2、由于cx不能寻址,所以还需要一个bx来scratch(就是不需要callee-save的寄存器)

具体的调用约定
1、__cdecl
名字修饰在函数前加下划线可能是为了区别函数名和汇编语言的关键字

2、__pascal
自左至右传参、callee cleanup
比较有意思的是名字修饰把函数名转换为大写,嗯,pascal大小写无关……
几乎所有的win16函数都是用pascal调用约定,因为callee-clean的操作比caller-clean要节省3bytes的空间

3、__fortran
和pascal一样

4、__fastcall
和win32下一样,把ecx、edx换为cx、dx罢了
这个fast可是未必,如果函数中的计算要用到cx、dx就免不了把cx、dx压栈的操作了,所以这种调用约定仅仅可能对短小的leaf function(就是不调用其他函数的函数)快一些,甚至对这类函数都快不了……

 

Microsoft函数调用约定的更多相关文章

  1. C语言函数调用约定

    在C语言中,假设我们有这样的一个函数: int function(int a,int b) 调用时只要用result = function(1,2)这样的方式就可以使用这个函数.但是,当高级语言被编译 ...

  2. 函数调用约定_stdcall[转]

    关键字 清理堆栈 参数入栈顺序 函数名称修饰(C) __cdecl 调用函数 右 à 左 _函数名 __stdcall 被调用函数 右 à 左 _函数名@数字 __fastcall 被调用函数 右 à ...

  3. Windows x64汇编函数调用约定

    最近在写一些字符串函数的优化,用到x64汇编,我也是第一次接触,故跟大家分享一下. x86:又名 x32 ,表示 Intel x86 架构,即 Intel 的32位 80386 汇编指令集. x64: ...

  4. 【黑客免杀攻防】读书笔记7 - 软件逆向工程基础1(函数调用约定、Main函数查找)

    0x1 准备工作 1.1.准备工具 IDA:交互式反汇编工具 OllyDbg:用户层调试工具 Visual Studio:微软开发工具 1.2.基础知识 C++开发 汇编语言 0x2 查找真正的mai ...

  5. 汇编  cdecl 函数调用约定,stdcall 函数调用约定

    知识点:  cdecl 函数调用约定  stdcall 函数调用约定  CALL堆栈平衡 配置属性--> c/c++ -->高级-->调用约定 一.cdecl调用约定 VC++ ...

  6. 关于函数调用约定-thiscall调用约定

    函数调用约定描述了如何以正确的方式调用某些特定类型的函数.包括了函数参数在栈上的分配顺序.有哪些参数将通过寄存器传入,以及在函数返回时函数栈的回收方式等. 函数调用约定的几种类型 stdcall,cd ...

  7. C/C++函数调用约定与this指针

    关于 C/C++ 函数调用约定,大多数时候并不会影响程序逻辑,但遇到跨语言编程时,了解一下还是有好处的. VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调 ...

  8. c++中的几种函数调用约定(转)

    C++中的函数调用约定(调用惯例)主要针对三个问题: 1.参数传递的方式(是否采用寄存器传递参数.采用哪个寄存器传递参数.参数压桟的顺序等): 参数的传递方式,最常见的是通过栈传递.函数的调用方将参数 ...

  9. 关于 C/C++ 函数调用约定

    关于 C/C++ 函数调用约定,大多数时候并不会影响程序逻辑,但遇到跨语言编程时,了解一下还是有好处的. VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调 ...

随机推荐

  1. 【Todo】C++和Java里面的浮点数及各种数字表示

    今天看了这篇文章,是讲C++中的浮点类型的:<浮点数的二进制表示> 再复习一下Java里面的Float和Double. 首先,直接数字赋值给Float变量是不行的,数字后要加上F,这样写: ...

  2. topcoder srm 552

    div1 250pt: 题意:用RGB三种颜色的球摆N层的三角形,要求相邻的不同色,给出RGB的数量,问最多能摆几个 解法:三种颜色的数量要么是全一样,要么是两个一样,另外一个比他们多一个,于是可以分 ...

  3. How To Configure a Redis Cluster on Ubuntu 14.04

    原文:https://www.digitalocean.com/community/tutorials/how-to-configure-a-redis-cluster-on-ubuntu-14-04 ...

  4. [Angular] Communicate Between Components Using Angular Dependency Injection

    Allow more than one child component of the same type. Allow child components to be placed within the ...

  5. 微信小程序 自定义组件(modal) 引入组件

    项目结构: 步骤一:创建组件 声明这一组文件为自定义组件 modal.json { "component": true, // 自定义组件声明 "usingCompone ...

  6. React Native入门——布局实践:开发京东client首页(一)

    有了一些对React Native开发的简单了解,让我们从实战出发.一起来构建一个简单的京东client. 这个client是仿照之前版本号的京东client开发的Android版应用,来源于CSDN ...

  7. 嵌入式linux 实现mdev SD卡和U盘自己主动挂载和卸载的方法 mdev.conf

    首先先參考这些博客做一些了解:http://linux.chinaunix.net/techdoc/install/2009/11/18/1144936.shtml http://www.cnblog ...

  8. 识别jar的编译JDK版本

    解压jar,获取xxx.calss文件 dos命令行javap -verbose classname import java.io.InputStream; import java.io.PrintW ...

  9. Oracle - 数据更新 - 增删改

    /* 数据的更新 增加 删除 修改 */ -----------------------------------增加(一次只能插入一条数据) --自定义插入数据列的顺序 ,,); --按照数据库默认的 ...

  10. 用 kGDB 调试 Linux 内核

    简介 这个文档记录了用kGDB调试Linux内核的全过程,都是在前人工作基础上的一些总结.以下操作都是基于特定板子来进行,但是大部分都能应用于其他平台. 要使用KGDB来调试内核,首先需要修改conf ...