• c语言中函数调用惯例


    调用惯例(Calling Convention):函数的调用方和被调用方对于函数如何调用需要有一个明确的约定,只有双方都遵守同样的约定,函数才能被正确的调用。

      调用惯例一般会涉及到一下三个方面:

    1 函数参数传递的顺序与方式

      函数传递参数的方式有很多中,可以通过寄存器、栈和内存区域传递,不过最常见的是通过栈传递。函数的调用方先将参数压入栈中,函数自己再从栈中取出参数。对于有多个参数的函数,调用惯例要规定调用方将函数压入栈的顺序:是从左到右,还是从右到左。有些惯例还允许通过寄存器传递参数,以提高性能。

    2 栈的维护方式

      在函数压入栈之后,函数体会被调用,此后需要将被压入栈中的参数全部弹出,以使得栈在函数调用前后保持一致。这个工作既可以由调用方来做,也可以由函数来做。

    3 名字修饰

      为了链接的时候对调用管理进行区分,调用管理要对函数本身的名字进行修饰。不同的调用管理有不同的名字修饰策略。

      这里我们主要介绍的cdecl、stdcall、fastcall三种c中主要的调用惯例,还有pascal、naked call、thiscall调用管理。这三种调用的区别如下:

    调用惯例 出栈方 参数传递 名字修饰
    cdecl 函数调用方 从右至左压入栈 下划线+函数名
    stdcall 函数本身 从右至左压入栈 下划线+函数名+@+参数的字节数
    fastcall 函数本身

    头两个DWORD(4字节)类型或者占更少

    字节的参数被放入寄存器,其它剩下的参数

    按从右至左的顺序压入栈

    @+函数名+@+参数的字节数

      下面用一个实际的例子来看看这些调用方式具体是怎么实现的:

     1 #include <stdio.h>
     2 
     3 void __attribute__ (( cdecl))
     4 a(int a, int b, int c) 
     5 {
     6     char buffer1[5];
     7     char buffer2[10];
     8 }
     9 
    10 int main ( int argc, char *argv[] )
    11 {
    12     a(1, 2, 3);
    13     return 0;
    14 }                /* ----------  end of function main  ---------- */

     

      编译上面的代码,然后反汇编看下main函数和a函数的汇编代码:

      从反汇编的代码中可以看出main函数调用a时,参数是通过栈传输的,并且是从右至左向栈中压。a函数并没有维护栈,但是main函数貌似也没有维护栈,其实不然,main函数是用mov指令代替了push指令,所以esp的值并没有改变,也就不必维护了。不过如果用push,那就要维护esp的值,在编译时加上“-mno-accumulate-outgoing-args”选项就可以看到这种情况。这种调用惯例是gcc默认的,也就是cdecl惯例。

      如果把上面代码中的第3行的cdecl换成stdcall,情况又会是怎样的呢?我们反汇编看下:


      确实可以在a函数中看到它用ret指令维护了堆栈。不过对于用mov实现栈参数压入的main来说却反而要维护esp了,由于a中让esp减了0xc,所以回到main中后就必须回复esp的值,这也是为什么call a后main中将esp加了0xc。

      如果把上面代码中的第3行的cdecl换成fastcall,情况又会是怎样的呢?我们反汇编看下:

      

      从main中可以看出,调用a函数的前两个参数分别通过ecx和edx传送,最后一个参数通过栈传送。a函数也维护了栈。

      pascal调用惯例是将参数从左至右传送,函数自己维护栈,函数命名比较的复杂,貌似gcc通过前面的方式设置这种惯例不行。

     

  • 相关阅读:
    ssh中Hibernate懒加载,session问题的学习与理解
    ligerUI---ListBox(列表框可移动)
    ligerUI---下拉菜单(menubar)动态显示(从后台获取数据)
    ligerUI---下拉框(Combobox)
    ligerUI---ligerGrid中treegrid(表格树)的使用
    Hibernate--使用xml配置映射关系
    Hibernate--使用注解配置映射关系
    ligerUI---ligerGrid默认选中checkbox
    ligerUI---ligerGrid分页排序的使用(从后台获取数据显示)
    手机屏幕尺寸与iOS开发坐标的关系
  • 原文地址:https://www.cnblogs.com/chengxuyuancc/p/3103956.html
Copyright © 2020-2023  润新知