粤ICP备11076303号  广州青年志愿者协会医疗服务总队 www.gzyld.org.cn
加入医疗队
加入志愿者

位置:GZ医疗队公益纪实公益站长系统软件

Linux 内核解读入门(2)


来源:      作者:      点击:次      时间:2007-03-20

 即为中断总控程序的入口地址;中断总控程序用汇编语言定义在/usr/src/linux/arch/i386/kernel/entry.S中;
3.中断总控程序主要负责保存处理机执行系统调用前的状态,检验当前调用是否合法, 并根据系统调用向量,使处理机
  跳转到保存在 sys_call_table 表中的相应系统服务例程的入口; 从系统服务例程返回后恢复处理机状态退回用户程序;
  而系统调用向量则定义在/usr/src/linux/include/asm-386/unistd.h  中;sys_call_table 表定义在
  /usr/src/linux/arch/i386/kernel/entry.S 中;  同时在 /usr/src/linux/include/asm-386/unistd.h 
  中也定义了系统调用的用户编程接口;
4.由此可见 ,  linux 的系统调用也象 dos 系统的  int 21h 中断服务,  它把0x80 中断作为总的入口, 然后
  转到保存在 sys_call_table 表中的各种中断服务例程的入口地址 , 形成各种不同的中断服务;
  由以上源代码分析可知,  要增加一个系统调用就必须在 sys_call_table  表中增加一项 ,  并在其中保存好自己
  的系统服务例程的入口地址,然后重新编译内核,当然,系统服务例程是必不可少的。
由此可知在此版linux内核源程序<2。2。5>中,与系统调用相关的源程序文件就包括以下这些:
1.arch/i386/boot/bootsect.S
2.arch/i386/Kernel/setup.S
3.arch/i386/boot/compressed/head.S
4.arch/i386/kernel/head.S
5.init/main.c
6.arch/i386/kernel/traps.c
7.arch/i386/kernel/entry.S
8.arch/i386/kernel/irq.h
9.include/asm-386/unistd.h

 当然,这只是涉及到的几个主要文件。而事实上,增加系统调用真正要修改文件只有include/asm-386/unistd.h
 和arch/i386/kernel/entry.S两个;

【三】 对内核源码的修改:
1.在kernel/sys.c中增加系统服务例程如下:
       asmlinkage int sys_addtotal(int numdata)
{
int i=0,enddata=0;
while(i<=numdata)
enddata+=i++;
return enddata;
}
  该函数有一个 int 型入口参数 numdata , 并返回从 0 到 numdata 的累加值;  当然也可以把系统服务例程放
  在一个自己定义的文件或其他文件中,只是要在相应文件中作必要的说明;
2.把 asmlinkage int sys_addtotal( int) 的入口地址加到sys_call_table表中:
  arch/i386/kernel/entry.S 中的最后几行源代码修改前为: 
...   ...
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork)            /* 190 */
.rept NR_syscalls-190
.long SYMBOL_NAME(sys_ni_syscall)
.endr
修改后为:  ...   ...
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork)            /* 190 */
/* add by I */
.long SYMBOL_NAME(sys_addtotal)
.rept NR_syscalls-191
.long SYMBOL_NAME(sys_ni_syscall)
.endr
3. 把增加的 sys_call_table 表项所对应的向量,在include/asm-386/unistd.h 中进行必要申明,以供
   用户进程和其他系统进程查询或调用:
增加后的部分 /usr/src/linux/include/asm-386/unistd.h 文件如下:
...   ...
#define __NR_sendfile 187
#define __NR_getpmsg  188
#define __NR_putpmsg   189     
#define __NR_vfork 190
/* add by I */
#define __NR_addtotal 191
4.测试程序(test.c)如下:
#include
#include

_syscall1(int,addtotal,int, num)

main()
{
int i,j;

do 
   printf("Please input a number\n");
  while(scanf("%d",&i)==EOF); 
if((j=addtotal(i))==-1)
   printf("Error occurred in syscall-addtotal();\n"); 
printf("Total from 0 to %d is %d \n",i,j);
}
对修改后的新的内核进行编译,并引导它作为新的操作系统,运行几个程序后可以发现一切正常;在新的系统下
对测试程序进行编译(*注:由于原内核并未提供此系统调用,所以只有在编译后的新内核下,此测试程序才能
可能被编译通过),运行情况如下:
$gcc -o test test.c
$./test
Please input a number
36
Total from 0 to 36 is 666
可见,修改成功;
而且,对相关源码的进一步分析可知,在此版本的内核中,从/usr/src/linux/arch/i386/kernel/entry.S 
文件中对 sys_call_table 表的设置可以看出,有好几个系统调用的服务例程都是定义在
  /usr/src/linux/kernel/sys.c 中的同一个函数:
asmlinkage int sys_ni_syscall(void)
{
return -ENOSYS;
}
例如第188项和第189项就是如此:
...   ...
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork)            /* 190 */
... ...
而这两项在文件 /usr/src/linux/include/asm-386/unistd.h 中却申明如下:
...   ...
#define __NR_sendfile 187
#define __NR_getpmsg 188 /* some people actually want streams */
#define __NR_putpmsg 189 /* some people actually want streams */
#define __NR_vfork 190
由此可见,在此版本的内核源代码中,由于asmlinkage int sys_ni_syscall(void) 函数并不进行任何操作,
所以包括 getpmsg, putpmsg  在内的好几个系统调用都是不进行任何操作的,即有待扩充的空调用; 但它们
却仍然占用着sys_call_table表项,估计这是设计者们为了方便扩充系统调用而安排的; 所以只需增加相应

新活动 回顶部
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
验证码: 点击我更换图片
最新评论 进入详细评论页>>