zoukankan      html  css  js  c++  java
  • C#中的函数(二) 有参有返回值的函数

    接上一篇 C#中的函数(-) 无参无返回值的函数

    http://www.cnblogs.com/fzxiaoyi/p/8502613.html

    这次研究下C#中的函数(二) 有参有返回值的函数

    依然写一个小例子,用来测试

    跟上一个例子差不多,区别就是MyFunction有二个参数a,b,返回二个数相加的值

    F5调试运行,中断后转到反汇编

    这里很明显看到不同了

    这里就得讲到参数传递的方式,参数从左向右依次存入寄存器ecx edx

    但是不同的编程语言有不同的传递参数的方式,有空再写一篇文章介绍下

    要是学过汇编的,到这里又有疑问了,要是每个实参都存储在寄存器中,那超过寄存器数量怎么办?

    有疑惑就得测试,这是一贯原则,好吧再开个工程,写一个3个参数的相同函数

    转到反汇编,Look一下, 第三个实参是直接压栈

    那如果五个参数呢,再写一个函数测试下

    到这就很明了了

    总结一下: 如果传递的实参数量小于2个使用的ECX EDX寄存器,如果大于2个参数,

    使用堆栈进行传递.

    OK,明白了参数传递的方式回到最开始的例子,进一步分析MyFunction函数内部

    F10单步执行二次,停在001F2DD5

    然后F11进入函数内部查看

    这里反汇编代码太长,就不截图了,直接贴反汇编代码

    001F2DF8 push ebp         //前面这二句用来保存esp
    001F2DF9 mov ebp,esp   //此时ebp指向栈顶
    001F2DFB push edi
    001F2DFC push esi
    001F2DFD push ebx   //对edi esi ebx寄存器压栈进行保存

    //这里开始就是我们研究的重点了,可以F10单步执行,顺带查看寄存器跟堆栈中值

    //上一篇中这里是sub esp,2ch,而这里是3ch

    //这里多出来的10h是返回值地址,二个形参地址,一个临时变量sum地址

    001F2DFE sub esp,3Ch //接合上面那三句,此时esp移动了0xC + 0x3C = 0x48个字节

    001F2E01 mov esi,ecx      //这个ecx 是1, 代表第一个实参,保存在esi中

    001F2E03 lea edi,[ebp-38h]   // 取地址操作esp + 0x10 = 从栈顶往下第四个位置
    001F2E06 mov ecx,0Bh           //这三行把0xB* 4 = 44个字节空间清零
    001F2E0B xor eax,eax       
    001F2E0D rep stos dword ptr es:[edi]
    001F2E0F mov ecx,esi           //把参数1保存在ecx 
    001F2E11 mov dword ptr [ebp-3Ch],ecx    // 把参数1保存在[ebp-0x3C] 处
    001F2E14 mov dword ptr [ebp-40h],edx    //把参数2保存在[ebp-0x40h]处
    001F2E17 cmp dword ptr ds:[0018C7A8h],0
    001F2E1E je 001F2E25
    001F2E20 call 71C6CB2D
    001F2E25 xor edx,edx
    001F2E27 mov dword ptr [ebp-48h],edx
    001F2E2A xor edx,edx
    001F2E2C mov dword ptr [ebp-44h],edx
    001F2E2F nop

    //这里就是具体计算的地方
    22: int sum = a + b; 

    001F2E30 mov eax,dword ptr [ebp-3Ch] //把第一个参数存储在eax中
    001F2E33 add eax,dword ptr [ebp-40h]  //然后通过add把eax + 第二个参数,结果就是1 + 2 = 3
    001F2E36 mov dword ptr [ebp-44h],eax  //然后把相加的结果放在临时变量中
    001F2E39 mov eax,dword ptr [ebp-44h]  //又从临时变量中取出结果放在eax(这句完全多余)
    001F2E3C mov dword ptr [ebp-48h],eax  //把结果放在返回值地址中. 有返回值情况下eax存储的都是返回值

    //这是当前堆栈中的情况

    //这后面的代码是当前函数返回时必须要做的堆栈平衡处理 

    001F2E3F nop
    001F2E40 jmp 001F2E42
    001F2E42 mov eax,dword ptr [ebp-48h]
    001F2E45 lea esp,[ebp-0Ch]
    001F2E48 pop ebx
    001F2E49 pop esi
    001F2E4A pop edi
    001F2E4B pop ebp
    001F2E4C ret

    多于二个参数时,也顺带看一下核心代码

    前面说过,多余二个参数时,前二个参数存储在寄存器ECX EDX中,后面的参数存储在堆栈中

    18: int sum = a + b + c + d;
    001A34B0 mov eax,dword ptr [ebp-3Ch]    //eax = 第一个参数
    001A34B3 add eax,dword ptr [ebp-40h]    //eax = eax + 第二个参数
    001A34B6 add eax,dword ptr [ebp+0Ch]   //eax += 第三个参数 直接从堆栈中取不需要再开辟栈空间
    001A34B9 add eax,dword ptr [ebp+8]       //eax += 第四个参数 直接从堆栈中取不需要再开辟栈空间
    001A34BC mov dword ptr [ebp-44h],eax   // 临时变量sum = 前四个数之和
    19: return sum;                          
    001A34BF mov eax,dword ptr [ebp-44h]   //把临时变量sum给eax
    001A34C2 mov dword ptr [ebp-48h],eax   //把结果放在返回值地址中. 有返回值情况下eax存储的都是返回值
    001A34C5 nop
    001A34C6 jmp 001A34C8

  • 相关阅读:
    逻辑回归与最大熵模型
    提升方法-AdaBoost
    Python中的类属性、实例属性与类方法、静态方法
    mysqldump详解
    12.python 模块使用,面向对象介绍
    11 python 内置函数
    10.函数的变量与返回值
    9. 函数的定义和参数,默认参数
    linux下iptables详解
    把linux下的yum源更换为阿里云的国内源
  • 原文地址:https://www.cnblogs.com/fzxiaoyi/p/8503231.html
Copyright © 2011-2022 走看看