科技动态 | 硬件广场 | 下载基地 | 网络教室 | 网络冲浪 | 科学博览 | 移动时代 | 手机上网 | 桌面壁纸 | 科技商情 |
#define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1))); \ if (__res >= 0) \ return (type) __res; \ errno = -__res; \ return -1; \ } 你并不需要理解这个函数的全部代码.他不过是调用中断0x80并把_syscall提供的参数(->1.2)传进去.name表示我们所需要的系统调用.(name被展开为__NR_name,这是在/asm/unistd.h中定义的).通过这个方法我们实现了brk函数.其他的拥有不同数量参数的函数通过其他的一些宏实现(_syscallX,X代表参数的个数).我个人用另一种方法来实现这个函数,看下面的例子: int (*open)(char *, int, int); /*声明一个函数原型*/ open = sys_call_table[SYS_open]; /*你也可以用__NR_open*/ 在这个方法中你并不需要使用任何syscall宏,你只需要使用sys_call_table中的函数指针就可以了.在网上,我发现这种构造用户空间函数的方法也被SVAT的著名的LKM传播者使用.依我的观点,这种方法是好一些的方法.但是你应该测试并且做出自己的判断. 当提供参数给这些系统调用时你要小心,他们需要这些参数在用户空间,而不是内核空间.阅读1.4来找到从内核空间拷贝到用户空间的方法. 一个很简单的实现这个的方法(在我看来是最好的方法)就是利用所需的寄存器.你必须知道linux通过利用段选择器来区别用户空间,系统空间等等.系统调用使用的参数都是通过数据段(DS)来寻址的.(我没有在1.4中提到这些,因为我觉得放在这里更合适) DS可以通过asm/segment.h中的get_ds()获得.因此如果我们设置段选择器为一个合适的值,我们就可以直接获得系统调用的参数.设置段选择器可以用set_fs(....)实现.但是要小心,在你获得系统调用的参数以后必须恢复FS的值.OK,现在让我们来看一段有用的代码: ->filename 是在我们的内核空间;比如说,一个我们刚刚创建的字符串 unsigned long old_fs_value=get_fs(); set_fs(get_ds); /*从这以后我们可以存取用户空间的数据*/ open(filename, O_CREAT|O_RDWR|O_EXCL, 0640); set_fs(old_fs_value); /*恢复fs.....*/ 在我看来,这是最简单也是最好的解决这个问题的方法.但是你必须亲自测试他(再一次:P).记住到目前为止我演示的几个函数(brk,open)都是通过很简单的系统调用实现的.你可以看一眼我们感兴趣那些系统调用列表(1.2);比如说,sys_socketcall和所有对sockets的操作的实现有关(创建,关闭,发送,接收......).因此在创建你自己的函数时要十分的小心.要常常看一看内核的源代码.
函数/宏 描述 int sprintf (char *buf, const char *fmt, ...); int vsprintf (char *buf, const char *fmt, va_list args); 用来格式化字符串的函数 printk (...) 与用户空间的printf一样 void *memset (void *s, char c, size_t count); void *memcpy (void *dest, const void *src, size_t count); char *bcopy (const char *src, char *dest, int count); void *memmove (void *dest, const void *src, size_t count); int memcmp (const void *cs, const void *ct, size_t count); void *memscan (void *addr, unsigned char c, size_t size); 内存函数 int register_symtab (struct symbol_table *intab); see I.1 char *strcpy (char *dest, const char *src); char *strncpy (char *dest, const char *src, size_t count); char *strcat (char *dest, const char *src); char *strncat (char *dest, const char *src, size_t count); int strcmp (const char *cs, const char *ct); int strncmp (const char *cs,const char *ct, size_t count); char *strchr (const char *s, char c); size_t strlen (const char *s); size_t strnlen (const char *s, size_t count); size_t strspn (const char *s, const char *accept); char *strpbrk (const char *cs, const char *ct); char *strtok (char *s, const char *ct); 字符串比较等操作的函数 unsigned long simple_strtoul (const char *cp, char **endp, unsigned int base); 将字符串转换成数字 get_user_byte (addr); put_user_byte (x, addr); get_user_word (addr); put_user_word (x, addr); get_user_long (addr); put_user_long (x, addr); 用来访问用户内存的函数 suser(); fsuser(); 检查超级用户权限的 int register_chrdev (unsigned int major, const char *name, struct file_o perations *fops); int unregister_chrdev (unsigned int major, const char *name); int register_blkdev (unsigned int major, const char *name, struct file_o perations *fops); int unregister_blkdev (unsigned int major, const char *name); 注册设备驱动的函数 ..._chrdev -> 字符设备 ..._blkdev -> 块设备 请记住这里的一些函数也可以通过1.5中提到的方法使用.但是你必须明白,当内核无偿提供了这些函数时,通过用户空间函数来使用他们没有什么意义. 随后你会看到这些函数(特别是字符串比较函数)很重要的应用.
摘自《赛迪网》 pragmatic/THC,(版本1.0)/文
|
|
版权所有 中华网 |