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

  • 相关阅读:
    IIS7中的几种身份鉴别方式(一)Basic身份验证
    IIS7中的几种身份鉴别方式(二)集成身份验证
    java集合
    SharePoint 2010中welcome page的设置细节
    SharePoint中使用Linq出现未将对象引用到实例化的解决方法
    SharePoint 2010中关于An error was encountered while retrieving the user profile的处理方式记录
    The Need for an Architectural Body of Knowledge
    The Softer Side of the Architect
    Event Receivers 学习小结
    使用SmtpClient发送带图片的邮件的代码实现
  • 原文地址:https://www.cnblogs.com/fzxiaoyi/p/8503231.html
Copyright © 2011-2022 走看看