Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1465455
  • 博文数量: 267
  • 博客积分: 3010
  • 博客等级: 少校
  • 技术积分: 3089
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 17:09
个人简介

尊天命,尽人事

文章分类

全部博文(267)

文章存档

2017年(6)

2015年(4)

2014年(27)

2013年(52)

2012年(59)

2011年(120)

分类: LINUX

2012-04-15 21:01:15

一、实验目的

学习Linux内核的系统调用,理解、掌握Linux系统调用的实现框架、用户界面、参数传递、进入/返回过程。阅读Linux内核源代码,通过添加一个简单的系统调用实验,进一步理解Linux操作系统处理系统调用的统一流程。

 

二、实验内容

在现有的系统中添加一个不用传递参数的系统调用。这个系统调用的功能是实现遍历进程。实验主要内容:

l  添加系统调用的名字

l  利用标准C库进行包装

l  添加系统调用号

l  在系统调用表中添加相应表项

l  sys_mysyscall的实现

l  编写用户态测试程序

 

三、主要仪器设备(必填)

Linux环境:utuntu10.10linux内核2.6.36

待编译内核:linux2.6.36

 

四、操作方法和实验步骤

1】下载并部署内核源代码

       此步已经在实验2中完成。

 

2】添加系统调用号

       系统调用号在文件unistd.h里面定义。这个文件在ubuntu10.10下位于/usr/include/asm/unistd_32.h。现在我们在unistd.h中添加我们的系统调用号:__NR_mysyscall,如下所示:

     #define __NR_mysyscall                                223      /*添加或修改为mysyscall */

/* 注意:不同版本的内核系统调用号不一样,您可以根据内核版本不同对系统调用号进行修改*/

       添加系统调用号之后,系统才能根据这个号,作为索引,去找syscall-_table中的相应表项。

 

3】在系统调用表中添加或修改相应表项

       我们知道,系统调用处理程序(system_call)会根据eax中的索引到系统调用表(sys_call_table)中寻找相应的表项。所以,我们必须在那里添加我们自己的一个值。

       2.6.36的内核下,只需要修改arch/x86/kernel/syscall_table_32.S。注意,修改该文件首先要切换到root权限,此外使用gedit打开该文件时注意它的扩展名是大写的S

    ……

在对应的位置修改或添加*/

234         .long sys_gettid

         .long sys_readahead                       /* 225 */

……

 

       到现在为止,系统已经能够正确地找到并且调用sys_mysyscall。剩下的就只有一件事情,那就是sys_mysyscall的实现。

 

4sys_mysyscall的实现

       里面。在这里,我们并没有在kernel目录下另外添加自己的一个文件,这样做的目的是为了简单,而且不用修改makefile,省去不必要的麻烦。

       mysyscall系统调用实现遍历系统中的所有的进程,并打印每个进程的进程名字,进程标识符,进程的状态和父进程的标识符。

       进程名字、pid、进程状态、父进程的指针在task-struct结构的字段中。在内核中使用printk函数打印有关变量的值。遍历进程可以使用next_task宏,init_task进程为0号进程。

  asmlinkage int sys_mysyscall(void)

{

              //在此处加入遍历进程的代码;

              return 0;

}

 

5】重新编译内核

       一定要重新编译内核。内核编译完成后,重新启动编译后的新内核。

 

6】编写用户态程序

       要测试新添加的系统调用,需要编写一个用户态测试程序(test.c)调用mysyscall系统调用。mysyscall系统调用中printk函数输出的信息在/var/log/message文件中。也可以在shell下用dmesg命令查看。

用户态测试程序可以用如下方法实现

圆角矩形标注: 系统调用号根据实验具体数字而定#include

# include

#define __NR_ mysyscall 223

int main()

{

syscall(__NR_mysyscall);    /*syscall(223)  */

//在此加入在屏幕输出每个进程相关信息的代码;

}

l  gcc编译源程序

# gcc –o test test.c

l  运行程序

# ./test

l  shell命令查看遍历进程输出的信息

#dmesg

 

五、实验结果和分析

【1】   ubuntu10.10下位于/usr/include/asm/unistd_32.h。现在我们在unistd.h中添加我们的系统调用号:__NR_mysyscall,如下图

 

231 #define __NR_mysyscall                     223   

 

 

 

2】在系统调用表中添加相应表项,即修改arch/x86/kernel/syscall_table_32.S。如下图

 

3sys_mysyscall的实现,我们把一小段程序添加在kernel/sys.c里面,如下图


其中task是进程结构指针,task->comm是进程名,task->pid是进程idtask->state是进程状态,task->parent->pid是进程的父进程id

 

4】重新编译内核。成功后,重启。此时,在启动项中有2.6.362.6.36old两个选项,其中新的内核是2.6.36。选择它并进入系统。至此,我们已经成功添加了一个自己的系统调用。

 

5】编写用户态程序test.c,代码如下

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#define __NR_mysyscall 223

int main()

{

syscall(223); //系统调用

time_t mytime;

char temp[40]; //缓冲区

char m_time[16]; //存放所需要的特定格式的当前时间

time(&mytime); //得到当前时间

strcpy(temp,ctime(&mytime));//把某种格式的当前时间的内容存入缓冲区

int i=0;

//对当前时间格式化使之与messages文件中时间格式对应

while(i<15)

{

m_time[i]=temp[i+4]; //从第4个字符开始复制

i++;

}

FILE *fp;

char ch2[16];

char mm;

fp=fopen("/var/log/messages","r"); //以流的方式打开文件

int flag=0;

while(!feof(fp))

{

mm=fgetc(fp);

if(mm=='\n' && flag==0)

{

fgets(ch2,16,fp); //得到某行的前16个字符,即时间

if(strncmp(ch2,m_time,15)==0) //判断是否与当前时间相同

{//如果messages中时间为当前时间则输出

fseek(fp,-15,SEEK_CUR);

flag=1;

}

}

if(flag==1 && mm!=EOF)

printf("%c",mm);

}

fclose(fp);

return 0;

}

    详细的注释见代码

 

    程序运行后得到的截图如下

 


       在终端输入dmesg后得到的截图如下


 

       使用gedit查看/var/log/message文件,截图如下

 

六、讨论、心得

1、编译过一次内核后,由于.o文件都在存在,所以第二次编译时间非常快,本次实验,编译只用了10分钟左右。

2、添加一个系统调用类似于MFC中添加一个自定义的消息,首先要注册这个消息,以便系统知道有这么个消息,然后用户在程序中才能使用它。

4、在2.6.36中,有unistd.hunistd_32.hunistd_64.h,其实unistd.h中的内容只有几句代码,用来判断要使用unistd_32.h还是unistd_64.h。所以,平时我们在编写程序时引入头文件unistd.h,其实是引入了unistd_32.h(前提是你的机器是32位的,64位的同理)。

3、在编写test.c时,通过搜索互联网、查看c语言的相关书籍以及和同学的探讨,深入理解和运用了相关的流文件函数,包括fopenfgetcfgetsfseek等。对c的流文件操作是这次实验收获最大的,尤其是文件指针的定位。

 

本文出自 “晓伟的sky” 博客,请务必保留此出处http://zjuedward.blog.51cto.com/1445231/465997

阅读(4265) | 评论(0) | 转发(0) |
0

上一篇:git config的运用

下一篇:Android核心库

给主人留下些什么吧!~~