计算机系统-函数调用约定/调用规范/传参方式
cdecl:使用栈传参,通常使用ax寄存器存放返回值,由调用方重置sp
stdcall:使用栈传参,通常使用ax寄存器存放返回值,由被调用方重置sp
fastcall:约定优先使用寄存器传递参数,其次使用栈,由不同的编译器实现,咱自己也可以实现一个
thiscall:入参的时候多了一个当前对象(this)指针
本文的示例代码在visual studio 2019下写的,下面是一段最简单不过的C代码
int add_function(int a,int b,int c) {return a + b + c;
}int main()
{int aa=add(1, 2, 3);
}
cdecl(C Declaration) 约定
将被调用的函数需要的参数,压栈,当被调用的函数执行完毕,调用方负责重置SP的高度
本例中,main方法调用add之前,先push 1,2,3,然后调用add_function,add_function执行完毕,由main负责重置SP
下面的代码是mian函数调用add_function前后的一波操作
push 3
push 2
push 1
call add_function(0371037h)
add esp,0Ch
mov dword ptr [aa],eax
下面的代码是add_function函数执行前后的一波操作
// 函数序言
push ebp
mov ebp,esp
sub esp,0C0h
// 开始执行a + b + c,并把结果放到eax中
mov eax,dword ptr [ebp+8]
add eax,dword ptr [ebp+0Ch]
add eax,dword ptr [ebp+10h]
// 函数尾声
mov esp,ebp
pop ebp
ret
下面把上述两端代码合并到一起
以上就是cdecl约定,需要记住的是调用方负责重置SP高度,在本例的代码是main中的add esp,0Ch
stdcall(Standard Call) 约定
ret x指令:将SP-x,逻辑代码为:sp=sp-x
将add_function函数前面加上_stdcall
,编译器会按照stdcall约定编译
int _stdcall add_function(int a,int b,int c) {return a + b + c;
}
编译之后,add_function函数的尾声部分汇编代码如下
mov esp,ebp
pop ebp
ret 0Ch ;此处和cdecl约定不同,cdecl直接ret,而此处ret 0Ch
main函数汇编代码片段如下
push 3
push 2
push 1
call add_function(07113CAh) ;此处call之后和cdecl约定不同,cdecl有个add esp,0Ch操作,而此处没有
mov dword ptr [aa],eax
通过上述代码已经发现,stdcall约定中重置SP操作是在被调用函数(本例add_function)中做的,这是和cdecl约定不同的地方
fastcall
约定优先使用寄存器传递参数,如果无法通过寄存器,则使用栈传递参数,没有统一实现方式,不同的编译器有不同的策略
thiscall
为面向对象语言设计的调用规范,传参的时候,多出了一个this引用,按照本例的add_function函数来说,例子中是传递3个int,而如果这个函数在一个C++对象中,那么实际传递的参数是4个,多出了一个当前对象的指针,在GCC编译器中使用栈传递这个指针,MSVC中使用ECX寄存器,那么很明显,Java中就是thiscall调用约定,至于重置sp是同cdecl还是stdcall,在vs中是同stdcall的,而java中的ret指令也同样是stdcall
计算机系统-函数调用约定/调用规范/传参方式相关推荐
- 任务(多线程并行)TFDMemTable内存表传参方式调用服务器返回的TDataSet
任务(多线程并行)TFDMemTable内存表传参方式调用服务器返回的TDataSet 服务器端: function TServerMethods1.getTFDDataSet ( const p ...
- vue 多层子组件调用父组件的方法(传参方式bind方法 或 注入 provide() {}方法)
一,传参方式bind的方法的使用 例: 1.ui作为一个对象 data() {return {ui:{}//ui作为一个对象} } 2.初始化中,给ui绑定一个方法editDesignTree,使用b ...
- 【python教程入门学习】Python函数定义及传参方式详解(4种)
这篇文章主要介绍了Python函数定义及传参方式详解(4种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.函数初识 1.定 ...
- Android:页面跳转传参方式一,页面跳转传参方式二
一.页面跳转传参方式一 跳转的过程如何传参:也就是页面之间如何传递参数,有点像函数调用如何传参,页面跳转也要传参. 复制一个工程 你要跳转,(现在的代码如下),intent 既然能设置跳转到哪个页面 ...
- axios链接带参数_axios常见传参方式
1:get请求 一般发送请求是这么写 axios.get('/user?id=12345&name=user') .then(function (res) { console.log(res) ...
- 1.函数的结构,调用,传参,形参,实参,args,kwargs,名称空间,高阶函数
1.函数的初识 初始函数 获取任意一个字符串的元素的个数 s1='dsjdkjkfefenga' count=0 for i in s1:count+=1 print(count) 获取列表的元素的个 ...
- DM8 jdbc调用存储过程传参list<实体类>
DM8 jdbc调用存储过程传参list<实体类> 一.前提 jdbc的连接串参数prepareOptimize,表示是否对预编译SQL做优化,取值true/false,默认false不开 ...
- python调用so库输出传入指针_python中使用ctypes调用so传参设置遇到的问题及解决方法...
问题 近日在做一组声纹聚类时,使用了另一团队同学开发的声纹距离算法.该算法对外提供的是一组so包,需要使用方自己去使用.在python中调用纯so包一般使用ctypes类库,用起来看起来简单但也有不少 ...
- promise Eslint sql传参方式 async-await
这是一篇学习笔记 各种融合的杂谈 Eslint学习 官网 中文教程 安装Eslint npm i eslint@latest g 配置文件 .eslintrc.json eslint --init e ...
最新文章
- java应用窗口大小_java 如何让程序窗口随屏幕大小改变 | 学步园
- SQL Server 2016新特性:列存储索引新特性
- Angular2入门教程-1
- leetcode 2. 两数相加
- 求最大连续子序列和——解法1 – 暴力出奇迹||解法2 – 分治
- ML之LassoRRidgeR:基于datasets糖尿病数据集利用LassoR和RidgeR算法(alpha调参)进行(9→1)回归预测
- 【深入Java虚拟机JVM 10】回收方法区
- No error message available, result code: E_FAIL(0x80004005)
- pip升级后Import Error:cannot import name main解决方案
- 将5:400等类型的数据转成哈希表
- JS正则表达式从入门到入土(7)—— 分组
- Atitit web 视频播放器classid clsid 大总结quicktime vlc 1 Classid的用处
- 正则表达式(用户名表单验证/验证座机号码/正则替换replace)
- 电脑开两个及以上微信
- 【微信小程序】Java岗面试12家大厂成功跳槽
- DialogUtils 弹出窗工具类
- iOS应用中增加emoji表情输入功能
- wps word打开是html,用Word打开WPS文件的两种方法,WPS文件如何打开?
- (自)协方差矩阵与互协方差矩阵简介
- Leaflet修改地图中心点定位
热门文章
- D. Little Artem and Dance
- JSP向Servlet传递数据以及与STM32、ESP8266通信过程
- wait与notify
- Spring Cloud基础入门
- sql server oracle特点,SQL Server 和 Oracle 以及 MySQL 有哪些区别
- 应用内评分_评分者信度
- 四年级打字计算机上册教案,2019四年级上信息技术教案(A)打字速度靠指法_泰山版教育.doc.docx...
- maven配置项目根路径_Maven基本概念——根目录、项目创建、坐标
- Spring Security OAuth2 授权失败(401)
- Java 使用Collections.reverse对list集合进行降序排序