调用函数栈针的浅析

先来看一个简单的例子:

#include <stdio.h>
#include <stdlib.h>

int sum(int _a, int _b)
{
	int c = 0;
	c = _a + _b;
	return c;
}

int main()
{
	int a = 10;
	int b = 20;
	int ret = 0;
	ret = sum(a, b);
	printf("%d\n", ret);
	system("pause");
	return 0;
}

我们知道:main函数也是由一个函数调用而来,开辟的一个函数栈针,调用main函数的是mainCRTStartup()函数,而该函数也有一个运行时堆栈,用esp【栈顶低地址】、ebp【栈底高地址】两个寄存器来维护。

现在编译上述代码,反汇编代码如下【vc++6.0开发环境下的反汇编代码】

 

//如下是从vc++6.0中截取的汇编指令
--- f:\vc\a\a.cpp  --------------------------------------------------------------------------------------------------------
10:
11:   int main()
12:   {
00401060   push        ebp                    【压栈:把ebp寄存器里面的地址压到栈顶,此时esp移动到栈顶】
00401061   mov         ebp,esp             【让ebp指向esp处,把esp地址赋给ebp】
00401063   sub         esp,4Ch              【esp 指向  esp - 4Ch  处】
00401066   push        ebx                       【压栈:把ebx内容压到栈顶】
00401067   push        esi                       【压栈:把esi内容压到栈顶】
00401068   push        edi                        【压栈:把edi内容压到栈顶】
00401069   lea         edi,[ebp-4Ch]             
0040106C   mov         ecx,13h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]             【上述四条指令意思是:将指定区域全部初始化为CCCC形式】
13:       int a=10;
00401078   mov         dword ptr [ebp-4],0Ah    【把 10 赋给 a 变量所在空间】
14:       int b=20;
0040107F   mov         dword ptr [ebp-8],14h     【把 20 赋给 b 变量所在空间】
15:       int ret=0;
00401086   mov         dword ptr [ebp-0Ch],0      【把 0 赋给 ret 变量所在空间】 
16:
17:       ret=sum(a,b);                                                【调用函数前先传参】
0040108D   mov         eax,dword ptr [ebp-8]            【把 b 变量内容赋给 eax寄存器】
00401090   push        eax                                           【压栈:把eax内容压到栈顶】
00401091   mov         ecx,dword ptr [ebp-4]              【把 a 变量内容赋给 ecx寄存器】
00401094   push        ecx                                             【压栈:把ecx内容压到栈顶】
00401095   call        @ILT+0(sum) (00401005)         【调用call指令之前,编译器悄悄地把call下一条指令地址保存在栈顶了】
0040109A   add         esp,8                                          【根据保存的地址CPU执行此条指令,让esp指向 esp+8 处】
0040109D   mov         dword ptr [ebp-0Ch],eax           【把eax保存的计算结果值放到ret变量空间内】
18:       printf("%d\n",ret);
004010A0   mov         edx,dword ptr [ebp-0Ch]               【接下来继续执行相关指令。。。】
004010A3   push        edx
004010A4   push        offset string "%d\n" (00424024)
004010A9   call        printf (00401200)
004010AE   add         esp,8
19:
20:       system("pause");
004010B1   push        offset string "pause" (0042401c)
004010B6   call        system (004010f0)
004010BB   add         esp,4
21:   }
004010BE   pop         edi
004010BF   pop         esi
004010C0   pop         ebx
004010C1   add         esp,4Ch
004010C4   cmp         ebp,esp
004010C6   call        __chkesp (00401280)
004010CB   mov         esp,ebp
004010CD   pop         ebp
004010CE   ret

--- f:\vc\a\a.cpp  ------------------------------------------------------------------------------------------
1:    #include<stdio.h>
2:    #include<stdlib.h>
3:
4:    int sum(int _a,int _b)
5:    {
00401020   push        ebp                   【压栈:把ebp寄存器里面的地址压到栈顶,此时esp移动到栈顶】
00401021   mov         ebp,esp              【让ebp指向esp处,把esp地址赋给ebp】
00401023   sub         esp,44h               【esp 指向  esp - 44h  处】
00401026   push        ebx                     【压栈:把ebx内容压到栈顶】
00401027   push        esi                      【压栈:把esi内容压到栈顶】
00401028   push        edi                       【压栈:把edi内容压到栈顶】
00401029   lea         edi,[ebp-44h]         
0040102C   mov         ecx,11h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]               【上述四条指令意思是:将指定区域全部初始化为CCCC形式】
6:        int c=0;
00401038   mov         dword ptr [ebp-4],0            【把 0 赋给 c 变量所在空间】    
7:        c=_a+_b;
0040103F   mov         eax,dword ptr [ebp+8]         【把 a 变量内容赋给 eax寄存器】
00401042   add         eax,dword ptr [ebp+0Ch]        【把 b 变量内容赋给 eax寄存器做相加运算】
00401045   mov         dword ptr [ebp-4],eax           【把eax寄存器 内容赋给 c 变量】
8:        return c;
00401048   mov         eax,dword ptr [ebp-4]              【把 c 变量内容赋给 eax寄存器】
9:    }
0040104B   pop         edi                 【出栈,esp向栈底移动一步】
0040104C   pop         esi                 【出栈,esp向栈底移动一步】
0040104D   pop         ebx                【出栈,esp向栈底移动一步】
0040104E   mov         esp,ebp        【让esp指向ebp处,把ebp地址赋给esp】   
00401050   pop         ebp   【出栈,ebp向栈底移动一步,此时拿到call指令的下一条指令的地址,ebp便指向了原函数栈底】 
00401051   ret                        

-------------------------------------------------------------------------------------------------------------------------------

 

函数调用过程图如下:画的不好,请多指导~

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vue2中,可以使用watch来调用函数。具体有三种方式可以实现: 第一种方式是直接在watch中定义一个监听处理函数,当所监听的数据发生变化时,该函数会被触发。例如,在Vue实例中可以这样写: ``` watch: { cityName(newName, oldName) { // 在这里执行函数的逻辑 } } ``` 第二种方式是在watch中使用字符串形式的方法名来指定要调用的函数。例如,在Vue实例中可以这样写: ``` watch: { cityName: 'Namechange' } ``` 这样,当cityName的值发生变化时,会调用Vue实例中的Namechange函数。 第三种方式是使用$watch函数进行调用。$watch函数是Vue的内置方法,用于添加一个数据监听,当所监听的数据变化时,执行指定的回调函数。例如,在Vue实例中可以这样写: ``` this.$watch('cityName', function(newName, oldName) { // 在这里执行函数的逻辑 }) ``` 总结起来,Vue2中watch可以通过定义监听处理函数、使用字符串形式的方法名或使用$watch函数来调用函数。这些方法都可以实现在数据变化时执行相应的逻辑操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [vue的watch监听函数](https://blog.csdn.net/wwf1225/article/details/106590301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [浅析vue 函数配置项watch及函数 $watch 源码分享](https://download.csdn.net/download/weixin_38663167/12949455)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值