跟踪系统调用之旅

简介: 想学linux  c开发的博友或者正在学的博友,当你们的代码里出现系统调用,比如read、write、open等。你怎么看、怎么想?有没有想一探究竟,深究一下系统调用的始终。准备好纸和笔,让我们开始系统调用跟踪之旅: 开始之前呢,先花费2分钟概览一下图(1),在你的头脑中做个快照,便于后面分析的理解,以read调用为例,展开分析。

想学linux  c开发的博友或者正在学的博友,当你们的代码里出现系统调用,比如readwriteopen等。你怎么看、怎么想?有没有想一探究竟,深究一下系统调用的始终。准备好纸和笔,让我们开始系统调用跟踪之旅:

开始之前呢,先花费2分钟概览一下图(1),在你的头脑中做个快照,便于后面分析的理解,以read调用为例,展开分析。
           
                 

read函数的声明位于头文件#include

原型为:ssize_t read(int fd, void *buf, size_t count)

read函数在用户空间的伪代码:
                       

说明:

4行,寄存器eax保存了read函数的系统调用号,在 文件include/asm-i386/unistd.h里有定义(#define __NR_read  3);第57行,将三个参数分别放入三个寄存器(通过寄存器来传递参数)

8行,执行系统调用,进入内核;

9行,获取eax寄存器所保存的函数返 回值。

8行是一个中断,执行完第8行后,已经进入了系统内核,中断向量表中记录0x80号的中断处理程序开始执行,中断向量表的初始化在arch/x86_64/kernel/traps.c中定义:
                   

如红框标注所示。IA32_SYSCALL_VECTOR是系统调用的中断号,在include/asm-x86_64/hw_irq.h中定义:
                   

正好是0x80。而system_call是系统调用的中断处理函数指针,用户执行int $0x80后会执行到这个函数,它在arch/x86_64/kernel/entry.S中定义:
                  
                  
                  

SAVE_ALL是一个宏,在这include/asm-x86_64/calling.h文件里定义:


                  

主要作用就是将各个寄存器压入栈中。

cmpl $(nr_syscalls), %eax比较eax的值是否大于等于nr_syscallsnr_syscalls是比最大有效系统调用号大1的值,在arch/i386/kernel/entry.S中定义:

                 

syscall_table_size就是系统调用表的大小(单位:字节),syscall_table_size其实是一个数组,数组里存放的是各个系统调用函数的地址,元素类型是long型,除以4刚好是系统调用函数的个数。

如果从eax寄存器传进来的系统调用号有效,那么就执行第12行,在系统调用表里找到相应的系统调用服务程序,sys_call_tablearch/i386/kernel/entry.S中定义:

                 





*sys_call_table(,%eax,4)指的是sys_call_table里偏移量为%eax*4上的那个值指向的函数,这里%eax=3,那么第5行的sys_read()函数就会被调用。sys_read()/fs/read_write.c中定义:

                   

asmlingage是一个宏,定义为:__attribute__((regparm(0))),作用是让这个函数只从栈上获取参数(因为之前的SAVE_ALL将参数压到了栈里面)。

 Fget_light:根据fd指定的索引,从当前进程描述符中取出相应的file对象,如果没有找到指定的file对象,则返回错误,如果找到了指定的file对象,则调用file_pos_read函数取出此次读写文件的当前位置。

   然后调用vfs_read执行文件读取操作,而这个函数最终调用file->f_op_read指向的函数[fs/read_write.c文件中],代码如下:

                   

接下来调用file_pos_write()更新文件的当前读写位置,调用fput_light更新文件的引用计数。最后返回读取数据的字节数。

思考:file->f_op_read指向的函数是哪个?鉴于篇幅,我们准备在下一篇博文详解,继而开始真正数据读取之旅。

   

当数据读取完毕,需要返回用户态。以下即为推出内核,恢复各个寄存器的值,然后返回用户态的过程。
                 
                 
                 
                 
当执行完中断处理程序后,后面会调用RESTORE_REGS来恢复各个寄存器:

RESTORE_REGS的定义:


                 
                 
                 

                RESTORE_INT_REGS的定义:


                 

       当你耐着性子看到这里,真诚的说一声谢谢。我的劳作是有意义的。我写这篇博文的本意就是让自己在头脑形成一条清晰的脉络,read系统调用的清晰脉络。在平时分析问题的时候,沿着这条清晰的脉络,将疑难一一排除。对了,写这篇博文时,我参照的系统内核源码版本是:
linux-2.6.0



      Good luck for you!

目录
相关文章
|
23天前
|
监控 Linux Shell
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
39 0
|
30天前
|
存储 安全 Linux
深入Linux进程内核:揭开进程工作原理的神秘面纱
深入Linux进程内核:揭开进程工作原理的神秘面纱
42 0
|
存储 监控 安全
深度剖析Linux进程的内部机制:一探/proc/pid的奥秘
深度剖析Linux进程的内部机制:一探/proc/pid的奥秘
78 0
|
1月前
|
传感器
如何使用中断处理过程
如何使用中断处理过程
9 1
|
5月前
|
NoSQL Linux
看懂GDB调试核心:剖析ptrace原理及其应用场景!(上)
看懂GDB调试核心:剖析ptrace原理及其应用场景!
|
2月前
|
NoSQL Java 编译器
|
2月前
|
算法 Ubuntu Linux
【操作系统】探究进程奥秘:显示进程列表的解密与实战
【操作系统】探究进程奥秘:显示进程列表的解密与实战
34 0
|
5月前
|
存储 NoSQL Ubuntu
看懂GDB调试核心:剖析ptrace原理及其应用场景!(中)
看懂GDB调试核心:剖析ptrace原理及其应用场景!
|
8月前
|
C语言
《计算机操作系统-第三章》之中断与系统调用
《计算机操作系统-第三章》之中断与系统调用
191 0
|
9月前
|
缓存 数据格式 流计算
xawtv涉及的vivid系统调用分析
xawtv涉及的vivid系统调用分析
143 0