鱼C论坛

 找回密码
 立即注册
查看: 2018|回复: 2

ret问题

[复制链接]
发表于 2012-12-15 18:15:17 | 显示全部楼层 |阅读模式
1鱼币
1. __cdecl
    这个是Visual C++中最最常用的调用约定,但是在代码里并不常见。为什么呢?原因就是它太常用了,VC把它作为了默认值,也就是说一个函数如果不声明任何的调用约定,那这个函数用的就是__cdecl。下面两句是等同的。
void f(int x);
void __cdecl f(int x);
现在让我们看看编译器到底怎么实现这种调用约定的。假设我们现在编译下面这段代码:

// 调用函数f1 f1(1, 2, 3, 4);// 函数f1的实现 int __cdecl f1(int a, int b, int c, int d){return a + b + c + d;}


编译后的反汇编是:
;调用函数f1,4个参数分别是1,2,3和4
00401093 push 4 ;参数从右到左开始压栈,先压最后一个
00401095 push 3 ;第3个参数压栈
00401097 push 2 ;第2个参数压栈
00401099 push 1 ;第1个参数压栈
0040109B call f1 (401005h) ;调用函数f1
004010A0 add esp,10h ;清除栈上的4个参数

;函数f1的实现
push ebp ;保存寄存器ebp
mov ebp,esp ;将当前栈指针赋值给ebp
mov eax,dword ptr [ebp+8] ;eax为参数a
add eax,dword ptr [ebp+0Ch] ;eax = eax + 参数b
add eax,dword ptr [ebp+10h] ;eax = eax + 参数c
add eax,dword ptr [ebp+14h] ;eax = eax + 参数d
pop ebp ;恢复寄存器ebp的值
ret ;函数返回,返回值是eax

可以看到清除参数的工作是由caller(调用者,就是调用函数f1的地方)来负责。因为我们一共有4个int的参数,每个int是 4个byte,一共16个byte,换算成16进制是10h,所以上面粗体的反汇编(add esp,10h),通过直接把esp加10h来清除4个参数。(esp是指向栈顶的寄存器)
如果上面的反汇编有困难的话,可以记住这么一句话:__cdecl是由调用者来清除栈上的参数。


问题
;;;;
1.CALL是把下一条指令IP入栈
2.;调用函数f1,4个参数分别是1,2,3和4
00401093 push 4 ;参数从右到左开始压栈,先压最后一个
00401095 push 3 ;第3个参数压栈
00401097 push 2 ;第2个参数压栈
00401099 push 1 ;第1个参数压栈
0040109B call f1 (401005h) ;调用函数f1
3.ret 返回的不是   ;第1个参数压栈的地址吗?????????

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-12-15 18:37:37 | 显示全部楼层
Call指令是先将EIP压栈,然后才JMP到 F1去的,所以,ret返回的是add esp,10的地址,欢迎纠错
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2015-8-29 10:28:35 | 显示全部楼层
{:1_1:}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-27 01:36

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表