用od分析_cdecl和_stdcall调用惯例的差异
1.调用惯例简要介绍
调用惯例,是在函数调用时如何传递参数和返回值的约定。
具体关注四个问题:
- 使用什么方式传递参数?(寄存器?栈?or both)
- 参数以何种方式入栈?从右到左?抑或从左到右?(如果需要用到栈传递参数的话)
- 使用什么方式传递返回值?(寄存器?栈?or both)
- 谁负责清理栈上参数?(调用者函数?被调用者函数?)
针对这四个问题,不同的调用惯例有不同的实现,当今比较主流的调用惯例有cdecl、stdcall、fastcall。这里我们只分析cdecl和stdcall。
调用惯例 | 传参方式 | 入栈顺序 | 传返回值 | 清栈者 |
---|---|---|---|---|
cdecl | 栈传参 | 从右到左压栈 | 寄存器(EAX首选) | 调用者函数 |
stdcall | 栈传参 | 从右到左压栈 | 寄存器(EAX首选) | 被调用者函数 |
可以看到,针对以上四个指标,这两种调用方式的差异只在清栈这一部分:cdecl约定由调用者函数负责清理栈上参数,stdcall则约定由被调用者函数清理栈。
那么这样看来我们的任务便很轻松了,不过抱着学习的心态,还是对前三种调用约定进行验证,就当拿od练手了。
2.[分析对象】—简单的main和sub函数
学习从简单的问题入手往往更有效率。
鉴于博主水平有限,这里也是先分析一下简单的main函数和sub函数的调用关系。后续学到新东西再继续跟进啦。
main函数:
int main(int argc, char *argv[]) {
return sub(2, 1);