china.com
主页
新闻
体育
游戏
文化
教育
健康
财经
科技
旅游
军事
娱乐
商贸
  科技动态 硬件广场 下载基地 网络教室 网络冲浪 科学博览 移动时代 手机上网 桌面壁纸 科技商情  


第一部分. 基础知识


1.5使用用户空间函数的方法


正如你在1.4中看到的我们利用一个syscall宏来构造我们自己的brk调用,就像我们从用户空间中调用一样,实际上那些用户空间的很多库函数(并不是所有的)都是通过这种syscall宏调用实现的,下面的代码显示了在1.4中调用的_syscall1(.....)宏。(摘自/asm/unistd.h)

#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的操作的实现有关(创建,关闭,发送,接收......).因此在创建你自己的函数时要十分的小心.要常常看一看内核的源代码.

1.6常用内核空间函数列表


在本文开始的时候我介绍过printk(....)函数.那是一个每个人在内核空间都可以使用的函数,可以叫做内核函数.这些函数是给那些需要复杂函数的内核开发者的,常常由一些库提供.下面的表列出了一些最为重要的我们常使用的函数:

函数/宏 描述

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)/文

 


科技检索


中华网推荐

  • 1000名医生在线咨询

  • 中国足球队官方网站

  • 鸦片玫瑰(新版)

  • 精选股票天地

  • 闪光的flash教程

  • 中华网汽车世界

  • 为你的爱情出谋划策

  • 网文精选——野百合集

  • 世界文化遗产在中国

  • 历届香港小姐风姿集




  • 网络教室编辑信箱
    版权声明 | 本站检索 | 联系方法 | 刊登广告 | 使用说明 | 关于中华网 | 豁免条款

    版权所有 中华网