zoukankan      html  css  js  c++  java
  • 2020-09-04:函数调用约定了解么?

    福哥答案2020-09-04:
    初级回答:

    stdcall和cdecl两者的参数传递顺序都是从右向左。
    不同点是stdcall在被调用函数 (Callee) 返回前,由被调用函数 (Callee) 调整堆栈。cdecl在被调用函数 (Callee) 返回后,由调用方 (Caller) 调整堆栈,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。

    中级回答:

    1.__stdcall
    在被调用函数 (Callee) 返回前,由被调用函数 (Callee) 调整堆栈
    参数从右向左压入堆栈。
    函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸。

    2.__cdecl
    在被调用函数 (Callee) 返回后,由调用方 (Caller) 调整堆栈。
    函数实参在线程栈上按照从右至左的顺序依次压栈。
    函数结果保存在寄存器EAX/AX/AL中
    浮点型结果存放在寄存器ST0中
    编译后的函数名前缀以一个下划线字符
    调用者负责从线程栈中弹出实参(即清栈)
    8比特或者16比特长的整形实参提升为32比特长。
    受到函数调用影响的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS
    不受函数调用影响的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS
    RET指令从函数被调用者返回到调用者(实质上是读取寄存器EBP所指的线程栈之处保存的函数返回地址并加载到IP寄存器)

    3.__fastcall
    __fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的。
    实际上__fastcall用ECX和EDX传送前两个DWORD或更小的参数,剩下的参数仍自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈。
    __fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@function@number,如double multi(double a, double b)的修饰名是@multi@16。
    __fastcall和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第1个参数进ECX,第2个进EDX,其他参数是从右向左的入栈,返回仍然通过EAX。

    fastcall调用约定和stdcall类似,它意味着:
    1) 函数的第一个和第二个DWORD参数(或者尺寸更小的)通过ecx和edx传递,其他参数通过从右向左的顺序压栈;
    2) 被调用函数清理堆栈;
    3) 函数名修改规则同stdcall。

    Fast Calling Convention,快速调用约定。通过使用寄存器解决效率问题。特点:
    函数参数部分通过寄存器传递,函数中最左的两个DWORD(寄存器大小是双字)或者更小的参数,通过寄存器传递。剩下的从右到左堆栈传递。 函数名改编:“@函数名@函数参数字节大小十进制”。 返回方式同__stdcall。

    4.__thiscall
    thiscall是唯一一个不能明确指明的函数修饰,因为thiscall不是关键字。它是C++类成员函数缺省的调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理,thiscall意味着:
    1) 参数从右向左入栈;
    2) 如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈;
    3) 对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈。

    主要用于解决this指针问题,使用寄存器传递this指针。返回方式同__stdcall.

    5.__nakedcall
    这是一个很少见的调用约定,一般程序设计者建议不要使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是,不能用return返回返回值,只能用插入汇编返回结果。

    6.__pascal
    基于Pascal语言的调用约定,参数从左至右入栈(与cdecl相反)。被调用者负责在返回前清理堆栈。 此调用约定常见在如下16-bit 平台的编译器:OS/2 1.x,微软Windows 3.x,以及Borland Delphi版本1.x。

    7.__vectorcall
    目的是用来优化浮点向量运算,intel处理器种有很多浮点向量寄存器,传统的调用约定(stdcall cdecl fastcall thiscall) 都是通过通用寄存器(ecx edx /rcx rdx r8 r9)以及堆栈进行参数传递,所以调用的时候,浮点参数需要从栈获取。

    要求尽可能在寄存器中传递参数。函数名改编为”@@函数名@参数字节数十进制”。这是微软自己添加的标准。

    8.syscall
    与cdecl类似,参数被从右到左推入堆栈中。EAX, ECX和EDX不会保留值。参数列表的大小被放置在AL寄存器中(?)。 syscall是32位OS/2 API的标准。

    9.optlink
    参数也是从右到左被推入堆栈。从最左边开始的三个字符变元会被放置在EAX, EDX和ECX中,最多四个浮点变元会被传入ST(0)到ST(3)中----虽然这四个参数的空间也会在参数列表的栈上保留。函数的返回值在EAX或ST(0)中。保留的寄存器有EBP, EBX, ESI和EDI。 optlink在IBM VisualAge编译器中被使用。

    10.__clrcall
    __clrcall是C++ .Net里面的。
    ***
    [评论](https://user.qzone.qq.com/3182319461/blog/1599174163)

  • 相关阅读:
    开不了的窗_____window.open
    IIS项目发布完整流程
    理解MVC模式
    ASP.NET MVC 基础(01)
    C#之线程和并发
    vue时间格式化
    windows 2013 datacenter 安装sql server2008 r2兼容性
    SQL Server DBA十大必备工具使生活轻松
    ORACLE主要的系统表和系统视图
    Oracle中spool命令实现的两种方法比较
  • 原文地址:https://www.cnblogs.com/waitmoon/p/13616168.html
Copyright © 2011-2022 走看看