在用户程序中怎样调用内核函数?

lcp 2002-11-27 09:19:34
加精
如题!
请各位大虾指点!高分酬谢!
...全文
711 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
wmrwinhap 2002-12-26
  • 打赏
  • 举报
回复
收藏
970361 2002-12-02
  • 打赏
  • 举报
回复
/* 在用户空间运行的模块*/

/*
* This is user program
* of ioctrl
* user ioctrl to control
* module myioctrl
* duan
* 2002-11-21
*/

#include "myioctrl.h"

#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>

int ioctrl_setmsg(int file_desc ,char *msg)
{
int ret_val ;

ret_val = ioctl(file_desc,IOCTRL_SET_MSG,msg) ;
if(ret_val<0)
{
fprintf(stderr,"ioctl set message error\n") ;
exit(-1) ;
}
return ret_val ;
}
int ioctl_getmsg(int file_desc,char *buf)
{
int ret ;
ret = ioctl(file_desc,IOCTRL_GET_MSG,buf) ;
if(ret < 0)
{
fprintf(stderr,"ioctl set message error\n") ;
exit(-1) ;
}
return ret ;
}

int main()
{
int file_desc ;
char *message = "hello world This is test of module " ;
char buf[80] ;

bzero(buf,sizeof(buf) );
file_desc = open(DEV_NAME,0) ;
if(file_desc < 0)
{
fprintf(stderr,"open file %s error \n",DEV_NAME) ;
exit(1) ;
}
ioctrl_setmsg( file_desc ,message) ;
ioctl_getmsg( file_desc,buf) ;

fprintf(stderr,"get message success ! \nmsg is %s\n",buf) ;
close(file_desc) ;
return 0 ;
}
970361 2002-12-02
  • 打赏
  • 举报
回复
这是一个简单的例子,可以参考一下吧
/*
* This is test of module
* of io control
* duan
* 2002-11-19
* 内核模块
* myioctl.c 文件
*/

#include <linux/kernel.h>
#include <linux/module.h>

#ifndef KERNEL_VERSION
# define KERNEL_VERSION(a,b,c) (((a)<<16) + ((b)<< 8) + (c))
#endif

#include <linux/fs.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
# include <asm/uaccess.h>
#endif

#include "myioctrl.h"

#define SUCCESS 0

#define BUF_LEN 80

static int dev_open_count = 0 ;
static char chr_buf[BUF_LEN] ;
static char *curPtr ;

static int dev_open(struct inode *inode, struct file *file)
{
if(dev_open_count)
return -EBUSY ;

dev_open_count++ ;

curPtr = chr_buf ;
MOD_INC_USE_COUNT;
return SUCCESS ;
}

static int dev_release(struct inode *inode, struct file *file)
{
printk("<1> char dev close ") ;
dev_open_count-- ;
MOD_DEC_USE_COUNT ;
return 0 ;
}

static ssize_t dev_read(struct file *file, char *buf, size_t len, loff_t *offset)
{
int ret ;
if(!*curPtr)
return 0 ;

while(len && curPtr)
{
put_user(*(curPtr++) , (buf++) ) ;
len-- ;
ret++ ;
}
return ret ;
}
static ssize_t dev_write(struct file *file, const char *buf, size_t len, loff_t *offset)
{
int i ;
for(i=0; i<len && i<BUF_LEN; i++)
{
get_user(chr_buf[i] ,buf+i) ;
}
curPtr = chr_buf ;
return i ;
}

static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long param)
{
int i ;
char *tmp ;
char ch ;
switch(cmd)
{
case IOCTRL_SET_MSG:
tmp = (char*)param ;

/* get length of msg
* and store in i
*/
for(i=0; ch && i<BUF_LEN; i++)
get_user(ch,tmp) ;

dev_write(file,(char*)param,i,0) ;
break ;

case IOCTRL_GET_MSG:
i = dev_read(file, (char *)param, BUF_LEN-1 , 0) ;
put_user('\0',(char *)(param +i) ) ;
break ;

case IOCTRL_GET_BYTE:
if(param < BUF_LEN )
return chr_buf[param] ;
break ;
} /* end switch */

return SUCCESS ;
}

struct file_operations fops = {
NULL ,
NULL ,
dev_read,
dev_write,
NULL ,
NULL ,
dev_ioctl,
NULL ,
dev_open,
NULL ,
dev_release
};

int init_module()
{
int ret ;

ret = register_chrdev(_MARJO,DEV_NAME,&fops) ;

if(ret < 0)
{
printk("<1> init module error! \n"
"error code is %d" , ret) ;
return ret ;
}
printk ("%s The major device number is %d.\n",
"Registeration is a success",_MARJO);
printk ("If you want to talk to the device driver,\n");
printk ("you'll have to create a device file. \n");
printk ("We suggest you use:\n");
printk ("mknod %s c %d 0\n", DEV_NAME, _MARJO);
printk ("The device file name is important, because\n");
printk ("the ioctl program assumes that's the\n");
printk ("file you'll use.\n");

return SUCCESS ;
}

void cleanup_module()
{
int ret ;
ret = unregister_chrdev(_MARJO,DEV_NAME) ;
if(ret < 0)
printk(" unregister module error") ;
}

/*************************************************/
/* *.h 文件*/
/*
* This is test of module
* of io control
* duan
* 2002-11-19
*/

#ifndef MYIOCTRL_H_
#define MYIOCTRL_H_

#include <linux/ioctl.h>

#define _MARJO 100

#define IOCTRL_SET_MSG _IOR(_MARJO,0,char *)

#define IOCTRL_GET_MSG _IOR(_MARJO,1,char *)

/* 得到消息的第n个字节 */
#define IOCTRL_GET_BYTE _IOWR(_MARJO,2,int )

#define DEV_NAME "duan_dev"
#endif
970361 2002-12-02
  • 打赏
  • 举报
回复
做一个虚拟设备,比如字符设备文件,然后为这个字符设备编写驱动程序,在通过ioctl的不同命令来控制,这样做的好处就是不用覆盖掉别的系统调用,增加了一个设备,这个设备的作用就是调用内核函数。这方面的资料你找一些内核编程,或者是驱动开发的资料里面都有的。
lcp 2002-11-29
  • 打赏
  • 举报
回复
谢谢各位大虾!
970361(是猫就应该抓老鼠),
您能否就ioctl详细谈谈呢?谢谢!
lcp 2002-11-28
  • 打赏
  • 举报
回复
大虾,能否更详细解释一下呢?
我是初次接触kernel部分,谢谢!!!
970361 2002-11-28
  • 打赏
  • 举报
回复
还可以使用别的办法比如ioctl等,应该有很多方法的
970361 2002-11-28
  • 打赏
  • 举报
回复
以上代码你可以参考一下,不过要作为模块便衣,并且insmod到内核
970361 2002-11-28
  • 打赏
  • 举报
回复
你可以写一个内核模块,覆盖掉原来的系统调用,然后在这个模块中再调用内核函数

借用一下别人的代码,
哈哈
/* 标准头文件 */
#include <linux/kernel.h> /* 内核工作 */
#include <linux/module.h> /* 明确指定是模块 */

/* 处理 CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <sys/syscall.h> /* 系统调用列表 */

/* 为了当前进程结构,我们需要这个知道当前用户是谁 */
#include <linux/sched.h>




/* 在 2.2.3 版/usr/include/linux/version.h 包含该宏但 2.0.35 不包含
* 加入以备需要 */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif



#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
#include <asm/uaccess.h>
#endif



/* 系统调用表(函数表)。我们只将定义为外部的即可,当我们insmod的时候内核会为我们填充它 */
extern void *sys_call_table[];


/* 我们想侦察的UID - 将从命令行填充 */
int uid;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
MODULE_PARM(uid, "i");
#endif

/* 原始的系统调用的指针。我们保存它而不是调用原始函数是因为其他某人可能在我们之前可能已经代替了
* 原始的系统调用(sys_open)。注意这并不是100%安全的,因为如果另一个模块在我们之前代替了
* sys_open,然后当我们被插入内核,我们将调用那个模块里的函数-它可能在我们之前又被移除了。
*
* 另一个原因是我们不能得到 sys_open。 它是静态变量,因此是不可导出的。 */
asmlinkage int (*original_call)(const char *, int, int);



/* 因为某些原因,在 2.2.3 版中current->uid 为0而非真正的用户 ID。我试图找出什么地方错了,但
* 不能在短时间内完成,而且我很懒-因此我仅仅使用系统调用得到UID,这是进程使用的方法。
*
* 因为某些原因,在我重新编译内核后这个问题没有了。
*/
asmlinkage int (*getuid_call)();



/* 我们将用来代替 sys_open 的函数 (当你调用 open 系统调用时这个函数被调用)。为了得到精确的原型
* 连同参数的数目和类型,我们首先找到了原始的函数(在 fs/open.c 中)。
*
* 理论上,这意味着我们将局限于内核的当前版本。实际上,系统调用几乎从来没有变化
* (这将制造一场浩劫并且需要将所有的程序重新编译,因为系统调用是内核和进程的接口)。
*/
asmlinkage int our_sys_open(const char *filename,
int flags,
int mode)
{
int i = 0;
char ch;

/* 检查是否是我们要侦察的用户 */
if (uid == getuid_call()) {
/* getuid_call 是 getuid 系统调用,它给出调用我们的系统调用的进程的用户的UID。 */

/* 如果相关则报告文件 */
printk("Opened file by %d: ", uid);
do {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
get_user(ch, filename+i);
#else
ch = get_user(filename+i);
#endif
i++;
printk("%c", ch);
} while (ch != 0);
printk("\n");
}

/* 调用原始的 sys_open - 否则,我们将失去打开文件的能力 */
/* 也可以在此做你想要做的事情——调用内核函数 */
return original_call(filename, flags, mode);
}



/* 初始化模块 - 代替系统调用 */
int init_module()
{
/* 警告 - 现在可能太迟了,但可能对下次... */
printk("I'm dangerous. I hope you did a ");
printk("sync before you insmod'ed me.\n");
printk("My counterpart, cleanup_module(), is even");
printk("more dangerous. If\n");
printk("you value your file system, it will ");
printk("be \"sync; rmmod\" \n");
printk("when you remove this module.\n");

/* 将原始的函数指针保存在 original_call,然后用我们的our_sys_open代替系统调用表中的相应系统调用
*/
original_call = sys_call_table[__NR_open];
sys_call_table[__NR_open] = our_sys_open;

/* 为了得到系统调用foo的函数地址,使用 sys_call_table[__NR_foo] 。 */

printk("Spying on UID:%d\n", uid);

/* 得到 getuid 系统调用*/
getuid_call = sys_call_table[__NR_getuid];

return 0;
}


/* 清除 - 从/proc中注销相关的文件 */
void cleanup_module()
{
/* 将系统调用恢复原状 */
if (sys_call_table[__NR_open] != our_sys_open) {
printk("Somebody else also played with the ");
printk("open system call\n");
printk("The system may be left in ");
printk("an unstable state.\n");
}

sys_call_table[__NR_open] = original_call;
}
batizhou 2002-11-28
  • 打赏
  • 举报
回复
用户态下不能随便调用内核函数的,内核可以把一些常用的功能以系统调用的方式提供给你。如果用户态下可以随意调用内核函数的话,岂不天下大乱,要知道在内核态想干什么就干什么。
如果你一定要调用内核函数,可以修改内核向系统调用表中加些你想调用的东西,或是做个模块。
gaoxianfeng 2002-11-28
  • 打赏
  • 举报
回复
1.
# vi /usr/src/linux/kernel/sys.c
在文件的最后增加一个系统调用函数:
asmlinkage int sys_print_info(int testflag)
{
printk(" Its my syscall function!n");
return 0;
}
该函数有一个int型入口参数testflag,并返回整数0。
2.
vi /usr/src/linux/arch/i386/kernel/entry.S
把函数的入口地址加到sys_call_table表中:
.long SYMBOL_NAME(sys_print_info)
.rept NR_syscalls-191 (数字加一)
3
vi /usr/src/linux/include/asm/unistd.h
把增加的sys_call_table表项所对应的向量,在include/asm/unistd.h中进行必要申明,以供用户进程和其他系统进程查询或调用。
#define __NR_print_info 191
4
编译内核
#my.c
_syscall1(int,print_info,int,testflag)
main()
{
int i;
i= print_info(0);
if(i==0)
printf("i=%d , syscall success!n",i);
}
如果要在用户程序中使用系统调用函数,那么在主函数main前必须申明调用_syscall,其中1 表示该系统调用只有一个入口参数,第一个int 表示系统调用的返回值为整型,print_info为系统调用函数名,第二个int 表示入口参数的类型为整型,testflag为入口参数名。
970361 2002-11-27
  • 打赏
  • 举报
回复
内核函数是通过系统调用的,
系统调用的时候会检查权限
asm("int $0x80")来实现的

23,125

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧