荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: zzt (好好学习,天天向上), 信区: Linux
标  题: [转载]Module的编程
发信站: BBS 荔园晨风站 (Thu Feb 17 19:43:20 2000), 站内信件

发信人: xz (非飞), 信区: Linux
标  题: [转载]Module的编程
发信站: 一网深情 (Sat Jul 24 11:06:33 1999), 转信

发信人: flight (非飞), 信区: Linux
标  题: [转载]Module的编程
发信站: 幽幽黄桷兰 (Sat Jul 24 11:05:01 1999), 转信

                        Module的编程
    在实际的产品开发和系统维护工作中,常常需要修改系统中某些功能
或向系统中添加新功能。如修改系统调用或添加新的设备驱动程序、新的
文件系统类型等。这可以通过两种方法来实现。第一种是直接修改系统的
核心代码,然后重新编译生成新的核心。该方法的缺点是每做一次修改,
都需要对系统进行重新编译,这给新核心代码的调试带来了相当大的困难。
若系统管理员需要针对不同用户进行相应的配置,重新编译的工作量是巨
大的。另外,这也给计算机厂商将新功能提供给用户造成很大不便。第二
种方法是将对系统的修改制做成一个module,通过静态或动态地加载和卸
载该module来修改系统的行为。应用module技术,可以减小系统核心代
码的规模,而且在需要时才装入module可以减小系统所占用的硬件资源,
从而提高系统的性能。Module的代码在装入核心后,与核心中其它代码的
地位是相同的,这给代码的调试带来相当大的方便。若管理员需针对不同
用户进行相应的配置,只需修改module配置文件或在装载它时传递的参
数。当计算机厂商将新功能发布给用户时,只需发布实现该功能的module。
下面以修改系统调用为例说明进行module编程时需要做的工作。
    大多数情况下,用户对系统核心的行为的改变是通过修改相应的系统
调用来实现的。这主要是由于用户进程不能直接访问核心空间的内存、调
用核心的函数。若用户需要系统为它提供服务,主要通过系统调用。因为
系统调用是用户进程请求操作系统为它提供服务的接口。

系统调用的一般过程为:
1.用户需要进行系统调用时,必须以C语言函数的形式写一句系统调用宏
_syscallN()。
2.当进程执行到用户程序的系统调用命令时,实际上执行了由宏命令
_syscallN()展开的函数。_syscallN()宏将系统调用的参数由各通用寄存
器传递,然后执行INT 0X80,以核心态进入入口地址system_call。从
system_call入口的汇编程序的主要功能是:
  (1)保存寄存器当前值(SAVE_ALL);
  (2)检验是否为合法的系统调用;
  (3)根据系统调用表sys_call_table和EAX持有的系统调用号找出并转
入系统调用响应函数;
  (4)从该响应函数返回后,让EAX寄存器保存函数返回值,跳转至
ret_from_sys_call。
  (5)最后,在执行位于用户程序中系统调用命令后面余下的指令之前,若
INT 0X80的返回值非负,则直接按类型type返回;否则,将INT 0X80的
返回值取绝对值,保留在errno变量中,返回-1。

修改系统调用需要的工作:
    修改系统调用需要重新编写系统调用代码,这一般是用户代码结束后
调用核心原来的函数。既user code + original system call functio改系统
调用sys_open为例说明进行module编程的细节。

例子的实现细节
/*module.c*/
/* 包含的头文件*/
#include <linux/kernel.h>    /* 我们进行核心编程*/
#include <linux/module.h>   /* 我们进行module编程*/
#include <sys/syscall.h>     /* 得到系统调用表*/
#include <linux/sched.h>    /* 获得当前进程的指针*/

/*定义sysmbol_table*/
/*
符号表是该模块向核心其它模块提供的接口,其它模块可以利用该模块提
供的资源。insmod向核心添加模块时,调用sys_get_kernel_syms(struct
kernel_sym table)得到当前的核心的所有符号,完成符号之间的引用关系
*/
static struct symbol_table mymodule_syms = {
#include <linux/symtab_begin.h>
        X(mymodule_symbol1),
        X(mymodule_symbol2),
        ……
        X(mymodule_sysboln),
#include <linux/symtab_end.h>
};

/*外部变量定义*/
/*
 注意这里将它定义为extern, 表示它引用其他模块的symbol,由insmod
完成符号指针的定位
*/
extern type1 var1;

extern typen varn;
extern void *sys_call_table[];   /* 系统调用表中函数指针表*/

/*需要传递给该module的参数定义*/
/*
 模块中的变量的值可以在 insmod时进行赋值,或在moduble的配置文件
中指定, 如 insmod modulename var1=value1 var2=value2
*/
type1 var1;

typen varn;
int uid;  /* 我们想监视的用户ID */

/*其它变量*/
/*
 该模块使用的局部变量
*/
type1 var1;
……
typen varn;
asmlinkage int (*original_call)(const char *, int, int);
/*指向原来的系统调用函数的指针*/

/*用户自定义系统调用响应函数*/
/*
 当该模块装载后,所有进程调用sys_open()时,其实是调用该函数
*/
asmlinkage int our_sys_open(const char *filename, int flags, int
mode)
{
    /* 用户代码*/
if (uid == current->uid)
{  /* 该用户是我们监视的用户,作相应的工作*/
   actions;
}
    /* 调用原来的系统调用函数*/
    return original_call(filename, flags, mode);
}

/* init_module*/
/* 执行insmod时,调用sys_create_module()创建新的module, 然后调
用sys_init_modue()对 module进行初始化,在初始化中调用init_module()
函数*/
int init_module()
{
  /*登记符号表*/
  register_symtab(&mymodule_syms);
  original_call = sys_call_table[__NR_open];
  sys_call_table[__NR_open] = our_sys_open;
  return 0;
}

/* cleanup_module*/
/*
 当该module不在被使用时,核心通知守护进程调用(或用户手工调用)
rmmod将它卸载出核心。在卸载的过程中调用sys_delete_module(),该函
数调用cleanup_module(),完成退出工作
*/
void cleanup_module()
{
  /*其它清除代码*/

  /* 恢复原来的系统调用 */
  sys_call_table[__NR_open] = original_call;
}

make文件的描述:
#change it here or specify it on the "make" commandline
INCLUDE = /usr/include

CFLAGS = -D__KERNEL__ -DMODULE –O –Wall –I$(INCLUDEDIR)
# Extract version number from headers.
VER = $(shell awk –F\" '/REL/ {PRINT $$2}'
        $(INCLUDEDIR) / linux/version.h)
OBJS = example.o

all : $(OBJS)
example.o :  module.o

install :
   install –d  /lib/modules/$(VER)/misc/lib/modules/misc
   install –c  example.o /lib/modules/$(VER)/misc
   install –c  example.o /lib/modules/misc
clean :
   rm –f *.o  *~core
make文件涉及很多细节,这里不赘述了。可参见文献linux device driver。

总结
    module是a.out 或 elf 格式的目标文件,它不固定link到某一地址
开始运行。它可以根据需要在系统启动后动态地加载到系统核心之中。一
旦module载入核心后,它则成为核心代码的一部分,它与其它核心代码的
地位是相同的。超级用户可以通过insmod和rmmod命令显示地将module
载入核心或从核心中将它卸载。核心也可在需要时,请求守护进程(kerneld)
装载(调用insmod命令)和卸载(调用rmmod命令)module。通过动态地
将代码载入核心可以减小核心代码的规模,使核心配置更为灵活。若在调
试新核心代码时采用module技术,用户不必在每次修改后都需重新编译核
心和启动系统。但是应用module技术会对系统的性能和内存有一定的影
响。
    module通过符号表(symbol table)使用核心资源,核心将资源登记在
符号表中。当module装载时,核心利用符号表来解决module中资源引用
的问题。Linux 允许module堆栈(module stacking),既一个module可请
求其他module为之提供服务。若module的引用记数为0,用户则可将它
卸载出核心。系统释放分配给该module的系统资源,同时将该module提
供的符号从核心符号表中删除。用户可以通过module编程来改造操作系
统,如添加设备驱动程序、文件系统、修改和增加系统调用等。



--
※ 来源:.幽幽黄桷兰 bbs.cqupt.edu.cn.[FROM: 202.202.37.26]

--
※ 来源:.一网深情 bbs.uestc.edu.cn.[FROM: 202.202.37.26]

--
☆ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: bbs@192.168.1.11]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店