C and C++ Calling Convention

调用约定(Calling Convention) 是计算机编程中一个比较底层的设计,它主要涉及:

  • 函数参数通过寄存器传递还是栈?
  • 函数参数从左到右还是从右到左压栈?
  • 是否支持可变参数函数(vararg function or variadic function)。
  • 是否需要函数原型?
  • 调用者(caller)还是被调用者(called or callee)清理堆栈?

在C和C++中有几种调用约定:__cdecl, __stdcall, __fastcall, __thiscall, __clrcall, __vectorcall。下面对比下几种调用约定。

__cdecl

C Declaration Calling Convention,C声明调用约定。它是C和C++默认的调用约定。特点:

  • 堆栈由调用者清除(手动清除)。
  • 参数从右到左压栈。
  • 支持可变参数(函数自己并不知道自己有多少个参数,因此需要调用者来清除)。
  • 编译后函数名改编为:“_函数名”。如_funcname。

__stdcall

Standard Calling Convention,标准调用约定。特点:

  • 调用者清除堆栈。
  • 参数从右到坐压栈(和__cdecl一样),如果调用类的成员函数,最后压入this指针。
  • 需要一个函数原型,不支持变参函数。
  • 函数名改编:“_函数名@参数字节大小十进制”。如[email protected]。

__fastcall

Fast Calling Convention,快速调用约定。通过使用寄存器解决效率问题。特点:

  • 函数参数部分通过寄存器传递,函数中最左的两个DWORD(寄存器大小是双字)或者更小的参数,通过寄存器传递。剩下的从右到左堆栈传递。
  • 函数名改编:“@函数名@函数参数字节大小十进制”。
  • 返回方式同__stdcall。

__thiscall

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

__clrcall

__clrcall是C++ .Net里面的。

__vectorcall

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

总结

除了__cdecl(以及__clrcall),其他的都是被调用者清除堆栈。

时间: 2024-10-08 10:44:16

C and C++ Calling Convention的相关文章

function calling convention

这是2013年写的一篇旧文,放在gegahost.net上面 http://raison.gegahost.net/?p=31 February 19, 2013 function calling convention Filed under: c++ — Tags: C convention, C optimization, multi-thread — Raison @ 4:29 am (original works by Peixu Zhu) Function calling conven

从栈不平衡问题 理解 calling convention

最近在开发的过程中遇到了几个很诡异的问题,造成了栈不平衡从而导致程序崩溃. 经过几经排查发现是和调用规约(calling convention)相关的问题,特此分享出来. 首先,讲一下什么是调用规约. 函数调用规约,是指当一个函数被调用时,函数的参数会被传递给被调用的函数和返回值会被返回给调用函数.函数的调用规约就是描述参数是怎么传递和由谁平衡堆栈的,当然还有返回值. 名称 谁负责参数出栈 参数压栈顺序 Cdecl Caller(调用者) 从右往左 Pascal Callee(被调用者) 从左往

JAVA calling convention

http://stackoverflow.com/questions/28126082/where-does-the-jit-compiled-code-reside https://wiki.openjdk.java.net/display/HotSpot/Linker+methods+for+direct+method+handles http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/9989538b7507/src/share/vm/o

C编译器剖析_1.5 结合C语言来学汇编_指针、数组和结构体

让我们再来看一份C代码,及其经UCC编译器编译后产生的主要汇编代码,如图1.33所示,其中包含了数组.指针和结构体. 图1.33 数组.指针和结构体 按照C的语义,图1.33第9行的C代码是对局部数组number的初始化,需要把number[0]初始化为2015,而数组中的其他元素皆被初始化为0.UCC编译器采取的翻译方法是:先调用memset函数来把数组number所占的内存空间清0,然后再把number[0]设为2015,如图1.33的第17至24行所示.C库函数memset的API如下所示

MIT 操作系统实验 MIT JOS lab1

JOS lab1 嘿嘿,实验环境还是相当的友好的. 很多东西都准备好了.把重点放在理论的印证上面. MIT才是改变并引领世界的牛校,心神往之,吾身不能至啊~ 国内的北大,上交等学校的OS实验都是直接用的JOS,这点证据还是容易找的...说明什么,不言而喻咯... ----------------------------------------------------------------------------------------------------------------------

使用C语言扩展Python3

使用C语言扩展Python3.在Python3中正确调用C函数. 1. 文件demo.c #include <Python.h> // c function static PyObject * demo_system(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts =

Linux Kernel - Debug Guide (Linux内核调试指南 )

http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环

Windbg找出memory leak的一种笨办法

以下内容是转自 http://www.cnblogs.com/fbird/p/5889596.html 以前做项目碰到过一个问题,在客户的站点上面发现有严重的内存泄漏.幸运的是我们找到了重现的步骤,一轮下来大概有几十兆的泄漏,但是以下常规方法却没啥用. 用windbg把heap上面的object全部dump下来,和上一轮操作作比较,并不能发现什么有用的东西. 大对象heap上面也没啥有用的东西. 像.net memory profiler这种比较智能的工具也用不上,因为一轮操作下来已经能使工具o

VC编译连接选项详解(转)

大家可能一直在用VC开发软件,但是对于这个编译器却未必很了解.原因是多方面的.大多数情况下,我们只停留在“使用”它,而不会想去“了解”它.因为它只是一个工具,我们宁可把更多的精力放在C++语言和软件设计上.我们习惯于这样一种“模式”:建立一个项目,然后写代码,然后编译,反反复复调试.但是,所谓:“公欲善其事,必先利其器”.如果我们精于VC开发环境,我们是不是能够做得更加游刃有余呢? VC的处理流程,大致分为两步:编译和连接.源文件通过编译生成了.obj文件:所有.obj文件和.lib文件通过连接