免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1574 | 回复: 0

howto Linux 模块编译 [复制链接]

论坛徽章:
0
发表于 2010-01-01 03:29 |显示全部楼层

                                               
   开始内核之路呵呵linux 就是内核 linux 的代码是C代码为主,汇编和微码为辅 这是一个好消息但是 内核C代码是采用的高级C语言技巧写成的 看起来会很费劲 一旦熟悉后 会很有收获 我看了一点的确 采用的是 OO 设计 非常简约 如果通过读代码学习内核必定是毫无效率可言的 学习写内核模块因该是个捷径 内核模块的经典书籍 LDD 3 写的非常好 希望结交学习这本书的朋友 一起学习 。
   1-2 节 我的理解是作者站在很高的高度描述了下什么是linux 内核的编程环境 词汇很生动 我就不贴了 这本书网络上有下载的建议下E文中文翻译的基本上是火星语言=_=!!  我学习的线路很特别 一样陌生的东西 先慢慢熟悉在逐步深入没有必要开始就死啃code or 抱着 intel的手册硬上 现代软件是模块为基本代码我们只要熟悉接口就可以先玩起来鸟 不是吗?我们要测量地球到太阳的距离一定要用皮尺拉吗?一个道理 重点说下 我的办法 抓住特点
1. 并发
       在我们还没有搞懂内核之前脑子里面要有个概念并发这和我们多线程和多进程编程时一样的linux内核环境也是并发的可以翻阅下它的demo 基本上都有锁 锁的花样非常多  我们可以用多线程编程的模型来套这个环境但是要注意结合实际的状态
2.高效
     这是一个需要效率的地方 所有必须的C库函数都重写成适合内核态所以无需的部分剔除去这是一个没有C库的环境但是你也可以看见熟悉的身影比如 strcpy 。。。 printk  goto 非常的多
3.通信机制
     内核编程的目的是服务用户程序开发 书上说的就2种 copy_to_user copy_from_user 还有一种是
netfilter 应该不止 目前先写上吧
4. 模块化
    这是我们的主题 我们可以通过insmod modprobe 安装 /rmmod  卸载 模块 但是仔细想想很好玩的 一个内核模块要服务多个例程 (这不就是C/S 架构吗)模块实际上就是一个服务器程序 如果想深入了解的话可以分析 insmod的代码 我简单的看了下 里面有个叫 kobject 的东西 这是一个抽象的基类 因为是服务器程序还比需要有引用计数器 我都找到了这是我说的第二个方法 类比法你可以猜 边猜边看书效率比较高哈 linux给我们设计很多驱动模型 比如字符设备 管道设备 。。。 这些都是根据实际情况抽象得到的 但是写程序是非常details的东西所以还不是很轻松就能掌握的如果你写过服务器程序写模块也会很轻松。如果你学过MS COM接口那会更轻松
我们要开始写helloworld 模块了 首先要学下如何编译内核 ?
debian lenny 来说其他发行版本不知道 debian 编译内核非常方便 但是我走了弯路 MB 网上很多人瞎说什么 make xxx make xxx 基本都是胡扯 BS  
  
  先回答一个问题为什么要编译内核 这里有一个符号表的问题 为了安全期间内核的一些函数没有导出来你需要编译内核打开它方便调试 比如你需要 GDB 调试功能 那么你的内核镜像文件要有调试信息才可以 。。。但是作为发行版这些功能都是关闭的
你可以下载源代码树 apt-get install xxxx 这个大家都会 下载一个叫 fakeroot 的软件
下来的 tar 包 解开
  $ cd /usr/src/linux-source-2.6.26/
$ sudo cp boot/config-2.6.26-2-686 .config
  sudo make menuconfig 这个不说了自己Google 如何选
$ sudo make-kpkg clean
  $ sudo fakeroot make-kpkg --initrd --revision=custom.1.0 kernel_image 1个小时
  $ sudo fakeroot make-kpkg --initrd --revision=custom.1.0 kernel_headers FAST
如果没有错误 就会产生 2个包包 :)
//========================================================================
  sudo dpkg -i ../linux-image-2.6.26_custom.1.0_i386.deb
  sudo dpkg -i ../linux-headers-2.6.26_custom.1.0_i386.deb

  sudo reboot
如果你从 kernel 站下的包的话 我没有测试过 我乐观的估计下是可以的
贴一个我从CU 论坛上抄的 修了小bug 双链表的demo 模块 呵呵 贴下 就当我的 helloworld 了
/*
* *   I wrote a small kernel module to show how to use kernel double list
* * with  and aslo show how to read/write a file in kernel
* * level. First it read the data from file named test, and then use those
* * data to create a double list, and delete the first character 't'. last
* * it write the data back into file test1 with double list.
* *
* * by wzt       http://tthacker.cublog.cn
* *
* */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzt");
#define SRC_FILE        "/home/xxx/ldd3/ldd3-samples/kernel_study/A"
#define DST_FILE        "/home/xxx/ldd3/ldd3-samples/kernel_study/B"
#define BUFF            1
struct dic_struct {
        char data[BUFF];
        struct list_head dic_list;
};
typedef struct dic_struct dic_xx;
static dic_xx mem_chuck[512];
int mem_ptr=0;
struct dic_struct dic_head;
rwlock_t list_lock = RW_LOCK_UNLOCKED;
int create_dic_list(struct dic_struct *dic_head, char *file_name)
{
        struct dic_struct *new;
        mm_segment_t old_fs;
        struct file *file = NULL;
        char buf[BUFF];
        ssize_t bytes;
        file = filp_open(file_name, O_RDONLY, 0);
        if (!file)
                return -1;
        if (!file->f_op->read) {
                filp_close(file, NULL);
                return 0;
        }
        old_fs = get_fs();
        set_fs(get_ds());
        write_lock(&list_lock);
        while ((bytes = file->f_op->read(file, buf, BUFF, &file->f_pos)) > 0) {
#if 0
                new = (struct dic_struct *)kmalloc(sizeof(struct dic_struct),
                                GFP_ATOMIC);
                if (!new)
                        return 0;
#endif
                if(mem_ptr>512) return 0;
        new=&(mem_chuck[mem_ptr++]);
                strcpy(new->data, buf);
                list_add_tail(&new->dic_list, &dic_head->dic_list);
        }
        write_unlock(&list_lock);
        set_fs(old_fs);
        filp_close(file, NULL);
        return 1;
}
int k_write(struct dic_struct *dic_head, char *file_name)
{
        struct dic_struct *tmp;
        struct list_head *p;
        struct file *file = NULL;
        mm_segment_t old_fs;
        file = filp_open(file_name, O_WRONLY | O_CREAT, 0);
        if (!file)
                return -1;
        if (!file->f_op->write) {
                filp_close(file, NULL);
                return -1;
        }
        old_fs = get_fs();
        set_fs(get_ds());
        write_lock(&list_lock);
        list_for_each(p, &dic_head->dic_list) {
                tmp = list_entry(p, struct dic_struct, dic_list);
                if (!tmp)
                        continue;
                file->f_op->write(file, tmp->data, sizeof(tmp->data),
                                &file->f_pos);
        }
        write_unlock(&list_lock);
        set_fs(old_fs);
        filp_close(file, NULL);
        return 0;
}
void  print_dic_list(struct dic_struct *dic_head)
{
        struct dic_struct *tmp;
        struct list_head *p;
        read_lock(&list_lock);
        list_for_each(p, &dic_head->dic_list) {
                tmp = list_entry(p, struct dic_struct, dic_list);
                if (!tmp)
                        continue;
                printk("MYLOG %c", (tmp->data)[0]);
        }
        read_unlock(&list_lock);
}
void del_dic_list(struct dic_struct *dic_head, char *data)
{
        struct dic_struct *tmp;
        struct list_head *p;
        write_lock(&list_lock);
        list_for_each(p, &dic_head->dic_list) {
                tmp = list_entry(p, struct dic_struct, dic_list);
                if (!tmp)
                        continue;
                if (!strcmp(tmp->data, data)) {
                        list_del(p);
                        return ;
                }
        }
        write_unlock(&list_lock);
        return ;
}
/*
* param NO
* init modules
*/
static int __init
list_test_init(void){
        strcpy(dic_head.data, "a");
        INIT_LIST_HEAD(&dic_head.dic_list);
        if (create_dic_list(&dic_head, SRC_FILE) == -1)
                return 0;
        printk("MYLOG ...........................\n");
        print_dic_list(&dic_head);
        printk("MYLOG ...........................\n");
        del_dic_list(&dic_head, "t");
        print_dic_list(&dic_head);
        k_write(&dic_head, DST_FILE);
        return 0;
}
/*
*  quit moodules
*  param no
*
*/
static void __exit
list_test_exit(void){
        printk(KERN_ALERT "MYLOG kernel double list test over.\n");
        schedule();
}
module_init(list_test_init);
module_exit(list_test_exit);
kprobe 是一个runtime 调试工具 大家结合书籍学习资料很多慢慢看吧!
说下 kprobe kernel 给了例子 大家可以编译下 在 samples  里面有 kprobe 的 3个例子 你如果通过下面的 Makefile 是无法编译成功的
obj-m := kprobe-exam.o kretprobe_example.o
#other-objs=kall.o kprobe-exam.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
        $(MAKE) -C  $(KERNELDIR) M=$(PWD) modules
clean:
        rm -f *.ko *.o
你需要重新 编译内核 然后 导出函数 注意宏定义 你可以在autoconfig.h or .config 里面找
System.map 查kernel 的符号
说下解决办法 你必须安 linux/Documentation/kprobes.txt 设置好 menuconfig 参数 然后修改
EXPORT_SYMBOL(kallsyms_lookup_name); 在 kernel/kallsyms.c 加上就可以编译成功了至少lenny
是可以的
最后新年快乐 !
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/94090/showart_2136814.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP