c和汇编---函数

环境:VC++

作用:
函数是完成特定任务的独立程序代码单元

1、创建和使用函数

  • 函数原型:声明函数是什么类型,指明函数的返回值和函数接收的参数类型,函数和变量一样,有多种类型,任何程序在使用函数之前都要声明该函数的类型
  • 函数调用:表明在此处执行函数,执行到函数调用的语句时,程序会找到该函数的定义并执行其中的内容,执行完返回调用函数继续执行下一行
  • 函数定义:详细说明函数要干啥
#include "stdio.h"int add(int a,int b);	//函数原型int main(void)
{int a=1,b=1,sum=0;sum=add(a,b);		//函数调用printf("sum=%d\n",sum);return 0;
}//函数定义
int add(int a,int b)
{return a+b;
}

我们看看反汇编:
函数原型:
在这里插入图片描述
我们可以看出,函数原型这里没有生成机器码,这个是给编译器看得,告诉编译器这个函数的返回值和函数接收的参数类型,并在别处查看该函数类型,机器码是给CPU执行的,所以CPU执行到这里,不会干任何事情
函数调用:

8:        sum=add(a,b);       //函数调用
0040104D 8B 45 F8             mov         eax,dword ptr [ebp-8]
00401050 50                   push        eax
00401051 8B 4D FC             mov         ecx,dword ptr [ebp-4]
00401054 51                   push        ecx
00401055 E8 AB FF FF FF       call        @ILT+0(add) (00401005)
0040105A 83 C4 08             add         esp,8
0040105D 89 45 F4             mov         dword ptr [ebp-0Ch],eax

函数调用之前,我们可以看到会先把参数存放到栈里面,也就是a,b的值,然后到00401005地址执行,这个地址有个jmp语句,会跳转到函数的定义出执行
在这里插入图片描述
函数定义:

13:   //函数定义
14:   int add(int a,int b)
15:   {
004010A0 55                   push        ebp
004010A1 8B EC                mov         ebp,esp
004010A3 83 EC 40             sub         esp,40h
004010A6 53                   push        ebx
004010A7 56                   push        esi
004010A8 57                   push        edi
004010A9 8D 7D C0             lea         edi,[ebp-40h]
004010AC B9 10 00 00 00       mov         ecx,10h
004010B1 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
004010B6 F3 AB                rep stos    dword ptr [edi]
16:       return a+b;
004010B8 8B 45 08             mov         eax,dword ptr [ebp+8]
004010BB 03 45 0C             add         eax,dword ptr [ebp+0Ch]
17:   }
004010BE 5F                   pop         edi
004010BF 5E                   pop         esi
004010C0 5B                   pop         ebx
004010C1 8B E5                mov         esp,ebp
004010C3 5D                   pop         ebp
004010C4 C3                   ret

从上面的程序我们可以看出,函数定义会先把esp存放到栈里面,然后把esp的值给ebp,接着开辟一个40h的栈,然后把ebx、 esi、 edi存放到栈里面,接着在一些连续地址存放0CCCCCCCCh,把这些做好后,再执行函数定义里的语句。

16:       return a+b;
004010B8 8B 45 08             mov         eax,dword ptr [ebp+8]
004010BB 03 45 0C             add         eax,dword ptr [ebp+0Ch]

我们看看函数的最后

004010BE 5F                   pop         edi
004010BF 5E                   pop         esi
004010C0 5B                   pop         ebx
004010C1 8B E5                mov         esp,ebp
004010C3 5D                   pop         ebp
004010C4 C3                   ret

函数的最后,把函数开始存放这些寄存器的内容又给了他们,ebp的值给esp,ebp恢复函数之前的ebp,接着返回。与函数调用的作用是一样的

函数的作用只完成特定任务,其他什么都没变,从函数调用到函数定义,最后返回,看起来是只对了a和b的值进行了操作,其他啥都没变

总结:
函数原型没有生成机器码,告诉编译器我的参数是那些和返回值是那些,函数调用会把参数先压入栈,接着执行call到一个地址执行,这个地址有一个jmp命令,会到函数定义出执行,函数定义会先把一些寄存器先压入栈,然后给一些内存赋值,在最后又会把这些寄存器给弹出,恢复成原值,执行ret命令,返回调用函数继续执行下一行。

2、传值和传址的区别

首先我们要认识几个小知识

  • &运算符:取变量的存储地址
  • *间接运算符:取存储在指针指向地址上的值,也可以用来声明指针
  • 声明指针变量:类型 * 变量名,声明指针变量必须指定指针所指向变量的类型,因为不同变量类型占用不同的存储空间
#include "stdio.h"int add1(int a,int b);	//函数原型
int add2(int *a,int *b);	//函数原型
int main(void)
{int a=1,b=1,sum1,sum2;sum1=add1(a,b);		//函数调用printf("sum1=%d\n",sum1);sum2=add2(&a,&b);		//函数调用printf("sum2=%d\n",sum2);return 0;
}//函数定义
int add1(int a,int b)
{return a+b;
}int add2(int *a,int *b)
{return *a+*b;
}

传值:

8:        sum1=add1(a,b);     //函数调用
0040D786 8B 45 F8             mov         eax,dword ptr [ebp-8]
0040D789 50                   push        eax
0040D78A 8B 4D FC             mov         ecx,dword ptr [ebp-4]
0040D78D 51                   push        ecx
0040D78E E8 7C 38 FF FF       call        @ILT+10(add) (0040100f)
0040D793 83 C4 08             add         esp,8
0040D796 89 45 F4             mov         dword ptr [ebp-0Ch],eax

值传给eax寄存器,然后入栈

传址:

10:       sum2=add2(&a,&b);       //函数调用
0040D7AA 8D 45 F8             lea         eax,[ebp-8]
0040D7AD 50                   push        eax
0040D7AE 8D 4D FC             lea         ecx,[ebp-4]
0040D7B1 51                   push        ecx
0040D7B2 E8 5D 38 FF FF       call        @ILT+15(add2) (00401014)
0040D7B7 83 C4 08             add         esp,8
0040D7BA 89 45 F0             mov         dword ptr [ebp-10h],eax

把地址传给eax,然后入栈
我们知道传值不可以修改变量的值,而传址却可以,从汇编角度看,我们可以更加的清晰明白,传值只是将值传过去了,函数调用是去函数定义处执行,不知道变量在哪里,所以没办法修改,传地址到函数定义时就知道变量的地址在哪里了,所以能修改变量得内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python投骰子程序代码_用于双骰子(一个偏向一个法线)仿真的Python程序

python投骰子程序代码Here, we will be simulating the occurrence of the sum of the faces of two dice [i.e. dice(A) - 1, 2, 3, 4, 5 ,6 dice(B) - 1, 2, 3, 4, 4, 4, 5, 6, 6 ,6]. A dice is normal(each has an equal probability of occurrence) and another B dice i…

如何追踪每一笔记录的来龙去脉:一个完整的Audit Logging解决方案[上篇]

一、提出问题 在开发一个企业级 应用的时候,尤其在一个涉及到敏感数据的应用,比如财务系统、物流系统,我们往往有这样的需求:对于数据库中每一笔数据的添加、修改和删除,都需要有一个明确的日志,以便我们可…

执行shellcode的几种方式

首先写出汇编成功弹出计算器 #pragma comment(linker,"/section:.data,RWE") //data段可读写#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") //不显示窗口#pragma comment(linker,"/INCREMENTAL:…

cobaltstrike生成一个原生c,然后利用xor加密解密执行

首先cobaltstrike生成一个原生c,我的是: /* length: 797 bytes */ unsigned char buf[] "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c" "\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac…

这样就可以很方便的知道明天的天气了

今天在侧边栏加了一个实用的小东西——天气预报。它可以根据来访者的ip地址自动判断地区,并展现今天以及明天的天气预报。这样来看blog的时候就可以知道什么时候该去收衣服啦~哈哈!实现代码其实很简单。就是套一个IFRAME,里面套个…

压缩矩阵

压缩矩阵:指为多个值相同的元素只分配一个存储空间,对零元素不分配存储空间特殊矩阵:指具有许多相同矩阵元素或零元素,并且这些相同矩阵元素或零元素的分配有一定规律性 1、对称矩阵 对称矩阵:矩阵每个元素都有aijaj…

线性方程组 python_线性方程组的表示 使用Python的线性代数

线性方程组 pythonPrerequisites: 先决条件: Defining a Vectors 定义向量 Defining a Matrix 定义矩阵 In this article, we are going to learn how to represent a linear equation in Python using Linear Algebra. For example we are considering an equatio…

初步体验数据驱动之美---TreeView

1.前言继上一篇《WPF应用基础篇---TreeView》的发布之后,有部分朋问我关于里面一些基础应用的问题,可能是我写得不够详细,所以在这里,我想再次那文章中的案例来谈谈初步体验数据驱动之美,摆脱旧WinForm编程习惯(靠触发…

不可以!

描述 判断&#xff1a;两个数x、y的正负性。 要求&#xff1a;不可以使用比较运算符&#xff0c;即”<”,”>”,”<”,”>”,””,”!”。 输入 有多组数据&#xff0c;每组数据占一行&#xff0c;每一行两个数x&#xff0c;y。 x、y保证在int范围内。 输出 …

树的基本概念

0x01 树 树&#xff1a;n个结点的有限集合&#xff0c;n0&#xff0c;空树任何非空树只有一个根结点n个结点的树只有n-1条边&#xff08;除根结点&#xff0c;每个结点只有一个前驱&#xff0c;一个前驱一条边&#xff0c;根据这个算的&#xff09;有序树与无序树&#xff1a;…

小学计算机教学教师培训,例谈小学信息技术课堂的有效教学

例谈小学信息技术课堂的有效教学在社会的各个领域&#xff0c;大家都不可避免地会接触到论文吧&#xff0c;论文可以推广经验&#xff0c;交流认识。为了让您在写论文时更加简单方便&#xff0c;以下是小编整理的例谈小学信息技术课堂的有效教学的论文相关内容&#xff0c;供大…

C和汇编---数组

0x01 初始化数组 1、没有初始化数组 #include "stdio.h" int main(void) {int data[4];for (int i0;i<4;i){printf("%d\t",data[i]);}return 0; }不同系统&#xff0c;输出结果可能不一样&#xff1a; 反汇编&#xff1a; 4: int data[4]; 5…

操作系统 系统开销比率_操作系统中的最高响应比率下一个(HRRN)调度

操作系统 系统开销比率操作系统中的HRRN调度是什么&#xff1f; (What is HRRN Scheduling in Operating System?) HRRN is the abbreviation of Highest Response Ratio Next Scheduling. It is an optimal scheduling algorithm. HRRN是最高响应率下一个调度的缩写 。 这是…

利用堆栈做循环

程序&#xff1a; #include "stdio.h" int main(int argc,char *argv[]) {char *str"%d";printf("hello world");__asm{ log:lea eax,logpush eaxlea ebx,strpush ebxpush eaxcall printfret 8}return 0;}运行&#xff1a;一直死循环运行下去 …

c# 多线程异步demo

一个 c# winform 多线程异步demo&#xff0c;分享下。 因为例子都很简单&#xff0c;所以不多说明&#xff0c;自己下载吧。转载于:https://www.cnblogs.com/chaobao/archive/2011/08/18/CSharpSync.html

计算机编程要哪方面天赋,编程要哪门子天赋

开局一张图写代码真的需要天赋吗&#xff1f;有句话是这样说的&#xff1a;论大家的努力程度&#xff0c;远不到拼天赋的时候。我认为所谓的天赋&#xff0c;应该是行业内Top10%水平才需要天赋&#xff0c;比如Linux缔造者Linus Torvalds&#xff0c;苹果发明者斯蒂夫沃兹尼亚克…

C和汇编----字符串

字符串是以空字符&#xff08;\0&#xff09;结尾的char类型数组。 0x01 定义字符串和初始化 用双引号括起来的内容称为字符串字面量&#xff0c;也叫字符串常量&#xff0c;双引号中的字符串和编译器自动加入\0字符&#xff0c;都作为字符串存储在内存中 #include "st…

远控免杀专题2---msfvenom的隐藏参数

0x01 msfvenom简介 msfvenom是msfpayload和msfencode的结合体&#xff0c;与2015年6月8日取代了msfpayload和msfencode。在此之后&#xff0c;metasploit-framwork下面的msfpayload&#xff08;载荷生成器&#xff09;&#xff0c;msfencoder&#xff08;编码器&#xff09;&a…

转载CSDN - 从程序员到HR——面试经验分享

CSDN博客一周热文推荐&#xff0c;为您总结回顾过去一周的CSDN博客热门文章&#xff0c;推荐优质的博客作者&#xff0c;分享精华文章和优质博客。 [1] 谭海燕&#xff1a;北漂之惠普H3C面试经历 上一篇讲到了《北漂之百度面试》&#xff0c;今天跟大家分享我在H3C的面试经历。…

ai系统架构_人工智能中的模糊逻辑系统架构

ai系统架构The Fuzzy Logic System is a system which uses Fuzzy logic for reasoning. Fuzzy Logic is a very efficient method for performing human-like reasoning in conditions with uncertainty. 模糊逻辑系统是使用模糊逻辑进行推理的系统。 模糊逻辑是一种在不确定条…