使用模块添加系统调用失败

内核编译和嵌入式产品的设计与开发
回复
zk012
帖子: 1
注册时间: 2010-11-10 10:03
送出感谢: 0
接收感谢: 0

使用模块添加系统调用失败

#1

帖子 zk012 » 2010-11-10 10:14

我不想编译内核来添加系统调用,所以采用模块的形式。我模块编译,安装,卸载都可以,但是就是在使用调用自定义系统调用程序的时候返回-1,表示调用失败,是什么原因呢?下面是我的模块:

#include<linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include<linux/fs.h>
#include <linux/sched.h>
#define __NR_mycall 338

MODULE_LICENSE("GPL");

static int (*anything_saved)(void);

asmlinkage int sys_mycall()
{
printk("hello world\n");
return 100;
}

// 中断描述符表寄存器结构
struct {
unsigned short limit;
unsigned int base;
} __attribute__((packed)) idtr;


// 中断描述符表结构
struct {
unsigned short off1;
unsigned short sel;
unsigned char none, flags;
unsigned short off2;
} __attribute__((packed)) idt;

// 查找sys_call_table的地址
void change_sys_call_table(void)
{
unsigned int sys_call_off;
unsigned int sys_call_table;
char* p;
int i;

// 通过sidt指令获取中断描述符表寄存器的地址,这里面包含有idt表的首地址
asm("sidt %0":"=m"(idtr));
printk(KERN_ALERT "in addr of idtr: %x\n", &idtr);

// 通过idtr里面的idt的首地址+偏移获取0x80中断处理程序的地址,由于idt中的每个门是64位,所以要乘以8,系统调用是0x80项,所以偏移为8*0x80。
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
//通过这项idt找到system_call的函数地址
sys_call_off=((idt.off2<<16)|idt.off1);
printk(KERN_ALERT "in addr of idt 0x80: %x\n", sys_call_off);

// 从0x80中断服务例程中搜索sys_call_table的地址,即通过找到第一个call指令的机器码8514ff来获取sys_call_table
p=sys_call_off;
for (i=0; i<100; i++)
{
if (p =='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{

sys_call_table=*(unsigned int*)(p+i+3);
unsigned int* sys_call_table_address = &sys_call_table;
printk(KERN_ALERT "in addr of sys_call_table: %x\n", sys_call_table);

//备份系统调用表中修改的那一项
anything_saved = (int(*)(void))(sys_call_table_address[__NR_mycall]);
//将这一项替换成自己的函数
sys_call_table_address[__NR_mycall] = (unsigned long)sys_mycall;

return ;
}
}
}

void undo_sys_call_table(void)
{
unsigned int sys_call_off;
unsigned int sys_call_table;
char* p;
int i;

// 获取中断描述符表寄存器的地址
asm("sidt %0":"=m"(idtr));
printk("out addr of idtr: %x\n", &idtr);

// 获取0x80中断处理程序的地址
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
sys_call_off=((idt.off2<<16)|idt.off1);
printk(KERN_ALERT "out addr of idt 0x80: %x\n", sys_call_off);

// 从0x80中断服务例程中搜索sys_call_table的地址
p=sys_call_off;
for (i=0; i<100; i++)
{
if (p =='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{
sys_call_table=*(unsigned int*)(p+i+3);
unsigned int* sys_call_table_address = &sys_call_table;
printk(KERN_ALERT "out addr of sys_call_table: %x\n", sys_call_table);
//将系统调用表中这项还原回来
sys_call_table_address[__NR_mycall] = (unsigned long)anything_saved;

return ;
}
}
}

int __init init_addsyscall(void)
{
//模块被insmod后就调用这个函数修改sys_call_table
change_sys_call_table();
return 0;
}

void __exit exit_addsyscall(void)
{
//模块被rmmod后就还原sys_call_table
undo_sys_call_table();
}

module_init(init_addsyscall);
module_exit(exit_addsyscall);

下面是我的调用程序:

#include <linux/time.h>
#include <linux/unistd.h>
#include <stdio.h>

#define __NR_mycall 338

int main()
{
printf("%d\n",syscall(__NR_mycall));

return 0;
}

被这个问题弄晕了 :em20 :em20 ,各位大大帮帮忙啊。
回复

回到 “内核及嵌入式开发”