系统调用原理剖析

在其他博友的基础上做了自己的分析。如有不对,请大家指导,小弟的疑问,请博友们解答。谢谢。
本文针对read函数分析,其他的函数是同样的道理。
首先编写一个read程序,交叉编译:arm-linux-gcc -static -g read.c -o read
编译后反汇编,arm-linux-objdump -D –S >dump, 在dump文件中查找查找read的位置。
如下图所示:
这里写图片描述
会发现其调用了libc_read函数。在dump文件中查找该函数,如下所示:
这里写图片描述
如图中红线所示,上面一行是将3(后面可以知道3其实是系统调用编号,是系统调用中函数的唯一标识符,这个3是通过后面的取调用编号得到的)放入r7寄存器中,svc指令是系统调用指令,能够产生软中断swi,此时Pc指针会从用户空间指向内核空间(系统从用户态切换到内核态,即此时进入内核空间),进入内核空间后的有一个固定的入口进入内核中来,所有的系统调用都是如此,在entry-common.S文件中的entry(vector_swi)函数,由此也可以看出是通过swi软中断进入内核空间的,然后要取编号,如下所示:
这里写图片描述
………………………………………………………………………………
这里写图片描述
下面有一行代码:
Adr tbl, sys_call_table @load syscall table pointer
该句的含义是让表指针指向sys_call_table(),因此下面执行sys_call_table()。
如下所示:
这里写图片描述
找到syss_call_table(),如下所示:
这里写图片描述
但该文件定义在arc/sparc/kernel中,是架构相关代码,不是arm的kernel中的,是不是因为此时工作在内和空间,所以导致会从内核中的表中查询,不会从这里查询,不知道理解的对不对??。下一行有个头文件call.h,打开该文件如下:
这里写图片描述
每一个系统调用都有一个对应的编号,此时会从拿原来写入寄存器的编号在这个表中查找相同编号的系统调用,即此时从用户空间函数找到系统调用函数sys_read()函数。
那么系统调用函数又如何找到驱动中的函数呢??
在sourceinsight中直接找不到相关的代码,在Read_write.c文件中,如下所示:
这里写图片描述
找到SYSCALL_DEFINE3()read, , , , , , ,) ,此处是一个宏定义,该宏定义会将read转化为sys_read(),即会自动添加一个头。SYSCALL_DEFINE3中的3是指产生的sys_read()函数有3个参数,此处即变成了sys_read()的实现代码。
其中有一个struct file结构(每个打开的文件都会有一个该结构与之对应),该结构中包含fd,fops等信息。通过fd信息找到对应的找到对应的指针,进而调用vfs_read()函数,找到该函数:
这里写图片描述
可以发现红线标注的一行:找到f_op中的read设备方法,即实现了系统调用。

总结如下:
当用户空间使用read()函数时,首先是将调用编号放入寄存器中,通过svc指令产生swi软中断,由用户空间进入内核空间,进入内核空间时有统一的入口,然后取调用编号,进而查找sys_call_table()中对应的编号,进而找到对应的sys_read()函数, sys_read()会找到对应设备文件的struct_file()函数,从里面得到fd,再调用vfs_read(),vfs_read()即调用f_op中的read()设备方法。

猜你喜欢

转载自blog.csdn.net/shclyshcly/article/details/81637819