接上一篇 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

C#中的函数(二) 有参有返回值的函数的更多相关文章

  1. C#中的函数(一) 无参无返回值的函数

    分析下C#中的函数 先写一个小例子,一个静态函数,无返回值,无形参 在第17行与20行分别下断点 F5调试运行,此时中断在第17行MyFunction(), 在第17行右键反汇编,看下反汇编代码 这里 ...

  2. C++ //纯虚函数和抽象类 // 语法 virtual 返回值类型 函数名 (参数列表)=0 //当类中有了纯虚函数 这个类也称为抽象类

    1 //纯虚函数和抽象类 2 // 语法 virtual 返回值类型 函数名 (参数列表)=0 3 //当类中有了纯虚函数 这个类也称为抽象类 4 5 6 #include <iostream& ...

  3. Swift2.0语言教程之函数的返回值与函数类型

    Swift2.0语言教程之函数的返回值与函数类型 Swift2.0中函数的返回值 根据是否具有返回值,函数可以分为无返回值函数和有返回值函数.以下将会对这两种函数类型进行讲解. Swift2.0中具有 ...

  4. 慕课网-Java入门第一季-7-3 Java 中无参带返回值方法的使用

    来源:http://www.imooc.com/code/1579 如果方法不包含参数,但有返回值,我们称为无参带返回值的方法. 例如:下面的代码,定义了一个方法名为 calSum ,无参数,但返回值 ...

  5. 慕课网-Java入门第一季-7-2 Java 中无参无返回值方法的使用

    来源:http://www.imooc.com/code/1578 如果方法不包含参数,且没有返回值,我们称为无参无返回值的方法. 方法的使用分两步: 第一步,定义方法 例如:下面代码定义了一个方法名 ...

  6. Java 中带参带返回值方法的使用

    如果方法既包含参数,又带有返回值,我们称为带参带返回值的方法. 例如:下面的代码,定义了一个 show 方法,带有一个参数 name ,方法执行后返回一个 String 类型的结果 调用带参带返回值的 ...

  7. Java 中无参带返回值方法的使用

    如果方法不包含参数,但有返回值,我们称为无参带返回值的方法. 例如:下面的代码,定义了一个方法名为 calSum ,无参数,但返回值为 int 类型的方法,执行的操作为计算两数之和,并返回结果 在 c ...

  8. Java 中无参无返回值方法的使用

    如果方法不包含参数,且没有返回值,我们称为无参无返回值的方法. 方法的使用分两步: 第一步,定义方法 例如:下面代码定义了一个方法名为 show ,没有参数,且没有返回值的方法,执行的操作为输出 “ ...

  9. go语言基础之有参有返回值函数的使用

    1.有参有返回值函数的使用 示例1: package main //必须 import "fmt" //go官方推荐写法 func MaxAndMin(a, b int) (max ...

随机推荐

  1. oracle--oracle18C环境配置(一)

    一,硬件配置检查 使用以下命令确定服务器上的物理RAM大小: # grep MemTotal /proc/meminfo 如果系统中安装的物理RAM的大小小于所需的大小,则必须先安装更多内存,然后再继 ...

  2. Eclipse:设置自动补全,提高编程效率

    一.设置自动补全 1.进入eclipse的window里的perferences页面 2.找到java->Editor->Content Assist设置界面 3.在Auto activa ...

  3. lower_case_table_names与表格名称大小写的问题

    1 简介 在MySQL中,数据库对应数据目录中的目录.数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎).因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感 ...

  4. Word中怎么快速选中并组合多个文本框图形

    目的: 选中全部的文本框或者图形.图像,然后组合到一起 步骤: 点击开始(Home),点击右侧 选择--选择对象 (select -- select objects) -- 鼠标拖放框选图形 -- 右 ...

  5. 服务器个人环境下pytorch0.4.1编译warp-ctc遇到的问题及解决方法

    一.关于warp-ctc CTC可以生成一个损失函数,用于在序列数据上进行监督式学习,不需要对齐输入数据及标签,经常连接在一个RNN网络的末端,训练端到端的语音或文本识别系统.CTC论文 CTC网络的 ...

  6. 基于verilog的分频器设计(半整数分频,小数分频:下)

    第二种方法:对进行奇数倍n分频时钟,首先进行n/2分频(带小数,即等于(n-1)/2+0.5),然后再进行二分频得到.得到占空比为50%的奇数倍分频.下面讲讲进行小数分频的设计方法. 小数分频:首先讲 ...

  7. Mono 下的 ASP.NET 可以运行在哪些 Web 服务器上?

    Mono has an implementation of ASP.NET 2.0, ASP.NET MVC and ASP.NET AJAX. Quick Resources: ASP.NET FA ...

  8. 整理了八个开源的 Spring Boot 学习资源

    Spring Boot 算是目前 Java 领域最火的技术栈了,松哥年初出版的 <Spring Boot + Vue 全栈开发实战>迄今为止已经加印了 3 次,Spring Boot 的受 ...

  9. 【JVM】jmap命令详解----查看JVM内存使用详情

    linux获取java进程PID: https://www.cnblogs.com/sxdcgaq8080/p/10734752.html 如果命令使用过程中报错,可能解决你问题的方案: https: ...

  10. [转].NET Core前后端分离快速开发框架(Core.3.0+AntdVue)

    [转].NET Core前后端分离快速开发框架(Core.3.0+AntdVue) 目录 引言 简介 环境搭建 开发环境要求 基础数据库构建 数据库设计规范 运行 使用教程 全局配置 快速开发 管理员 ...