首页 > 代码库 > 从普通的函数调用到操作系统内核空间的访问
从普通的函数调用到操作系统内核空间的访问
从普通的函数调用到操作系统内核空间的访问
首先通过了解认识函数的原理来体会函数的调用
1)函数
首先什么是函数,函数是用于完成特定任务的程序代码自包含单元
(这里的自包含单元听着可能不懂,其实就是代码段{}花括号里面的每条代码,以分号结尾的集合,它们是为了完成某种特定的功能而去编写的程序)那么在为什么要使用函数,一般来说,函数的使用可以省略代码的重复编写,这里就涉及到函数的调用,当我们在编写一个程序时,可能会重复调用某个特定的功能去实现某种特定的现象或结果。那么就会考虑到函数怎么编写的问题以及通过什么样的方式才可以使用被调用的函数。
2)函数的一般编写形式(这里只是个人习惯以及别人可以看懂被调用函数是什么功能):
描述性的函数名字,形如 int led_on (void){.....},这样编写可以让人更明白这个函数的功能,他就是打开led灯的函数,这里的int表示这个函数的返回值是个int型的常数,他可以表示函数运行的结果,通过函数的执行结果的返回值可以知道函数的运行状态,一般return 0;表示一个函数的成功执行,return -1/1;表示函数在执行过程中出错处理,以更方便的来通知函数调用者,这个函数的功能有没有实现,
这里要注意的是函数的返回值,仅仅只能表示一个函数的执行状态,但是这也函数到底完成了什么样的功能,又是不一样的概念了,每个函数的实现什么样的功能只有在自己函数模块里才知道,当我们要使用某个函数的功能时有两种方式可以实现
1:通过函数的返回值即return函数来给被用者使用
2:这里会涉及到函数传参的概念:在函数传参的方式中有值传递和地址传递
当我们使用值传递的时候,比如通过传递俩值参数(实参)给调用函数,在被调用函数里通过两数交换,之后再在主函数里打印出来,你会发现两个数的值根本没有改变,这是为什么呢?被调用的函数内部的变量只具有局部变量,它的变量存放栈空间,当在函数调用完时,它会被释放,但是为什么通过地址传递,在被调用函数内实现两个数的交换,在主函数打印两个数时,会发现两个值已经改变了,在一个函数调用过程中又调用别的过程,其实一般栈空间有两个指针,分别是栈指针和帧指针,对于一个程序调用过程来说栈空间的栈指针是相对的,他用来存放一些存储变量和局部变量,而对于过程中调用的过程会涉及到帧指针,它用来存放一些参数和返回值,对于一个函数的调用,在函数调用和一般函数的压栈参数以及变量的圧栈顺序:第一个圧栈的是下一条指令的执行地址,多个参数(即对应在内存中的存储空间地址)以及return值,到这里都是BP帧指针,在调用圧栈时一般是固定的,下面存放的是一些局部变量,存储变量,是相对的SP栈顶指针来表示,当一个调用函数要用地址传递的时候,对应的是实际的地址信息,而在内部的操作,则表示地址相关的操作,改变的变量也是实在的改变,在操作结束时栈空间刷新被释放,但是当在一般文献说函数的返回值不可以返回数组名,其实实际也可以看到返回值的有相关信息,此时会疑问,只是在创建的栈空间,在上次的使用被释放,但是里面存了上次的操作值,只有在下次使用这块地址的空间时,才会刷新,造成这样的假象。
3)函数之间怎么建立通信的
当你在主函数中要用到调用的函数,此时你只要把你要调用的函数名和函数相应需要的参数填入就可以实现函数之间的调用和通信,那他又是怎么跳转到我们之前设定的被调用函数的,其实在编译器编译的时候会默认把每个不同的代码模块通过连接到对应的内存地址空间,而此时注意的就是对于一个函数名,相当于在汇编keil软件中通过声明函数入口形如_start或者在eclipse软件中的汇编格式.start,来告知编译器函数的入口地址(其实它仅仅只表示入口地址也就是函数体里第一条有效可执行指令)此时当我们在主函数中遇到调用的函数时,对于的在CPU处理器中的PC指针会跳转到被调用的函数入口去执行调用函数块内的代码块,此时我们要注意在一个函数代码块内的变量只具有局部性。
4)约定函数参数
Void char (char ch ,int num) 这样的形式表示提供什么样的接口,被调用者使用,只有调用者使用这样的类型才可以成功调用,这里的形参可以是一般的数据类型和指针型,根据不同类型的形参,在调用者之前会写入实际的参数,即实参,实参可以是一般的局部变量,也可以是地址相关的数值,如果传入的是int char 等表示要传入存储变量,而在传入地址的话,则会涉及到地址寄存器相关的操作。
5)内核空间的系统调用
上面说的调用只是用户空间的函数调用,当明白了用户空间的函数调用形式以及一般的约定,就可以用来理解内核空间的系统调用,在Linux管理的虚拟内存管理机制,在4G的虚拟空间划分为0~3G为用户空间,用来运行普通的应用程序,普通的函数调用也在这段地址空间执行的,当我们要调用内核的调用函数时,在Linux系统中为了不让编程者随便修改访问硬件设备,提出了硬件的保护机制,当我们要访问物理的设备磁盘时,会陷入内核空间,其实在陷入内核空间之前,CPU是通过软中断机制实现陷入内核空间的,当CPU取指到函数名是系统调用函数时,会跳到对应的软中断号去执行相关的操作,比如open一个文件,然后去执行读写相关的操作,其实在内核空间的程序执行也不是直接接触设备的,是通过VFS(虚拟文件系统)来进行相关的操作,在最后结束时会把对VFS的相关操作转变为对应的物理地址的相关设备操作,在通过内核进程的状态切换返回给应用的用户进程。
从普通的函数调用到操作系统内核空间的访问