《Linux内核修炼之道》精华分享与讨论(10)——模块机制与“Hello World!”

来源:互联网 发布:台湾军舰知乎 编辑:程序博客网 时间:2024/06/01 18:39

有一种感动,叫内牛满面,有一种机制,叫模块机制。显然,这种模块机制给那些Linux的发烧友们带来了方便,因为模块机制意味着人们可以把庞大的Linux内核划分为许许多多个小的模块。对于编写设备驱动程序的开发者来说,从此以后他们可以编写设备驱动程序却不需要把她编译进内核,不用reboot机器,她只是一个模块,当你需要她的时候,你可以把她抱入怀中(insmod),当你不再需要她的时候,你可以把她一脚踢开(rmmod)。 

于是,忽如一夜春风来,内核处处是模块。让我们从一个伟大的例子去认识模块。这就是传说中的"Hello World!",这个梦幻般的名字我们看过无数次了,每一次她出现在眼前,就意味着我们开始接触一种新的计算机语言了。(某程序员对书法十分感兴趣,退休后决定在这方面有所建树。于是花重金购买了上等的文房四宝。一日,饭后突生雅兴,一番磨墨拟纸,并点上了上好的檀香,颇有王羲之风范,又具颜真卿气势,定神片刻,泼墨挥毫,郑重地写下一行字:hello world) 

请看下面这段代码,她就是Linux下的一个最简单的模块。当你安装这个模块的时候,她会用她特有的语言向你表白:“Hello,world!”,而后来你卸载了这个模块,你无情抛弃了她,她很伤心,她很绝望,但她没有抱怨,她只是淡淡地说,“Goodbye,cruel world!”(再见,残酷的世界!)

/************ hello.c *********************/

     1 #include <linux/init.h>  /* Needed for the macros */
  2 #include <linux/module.h> /* Needed for all modules */
  3 MODULE_LICENSE("Dual BSD/GPL");
  4 MODULE_AUTHOR("fudan_abc");
  5
  6 static int __init hello_init(void)
  7 {
  8         printk(KERN_ALERT "Hello, world!/n");
    9         return 0;
   10 }
  11
   12 static void __exit hello_exit(void)
    13 {
   14         printk(KERN_ALERT "Goodbye, cruel world/n");
    15 }
   16
    17 module_init(hello_init);
    18 module_exit(hello_exit);
 

你需要使用module_init()和module_exit(),你可以称它们为函数,不过实际上它们是一些宏,你可以不用去知道她们背后的故事,只需要知道,在Linux Kernel 2.6的世界里,你写的任何一个模块都需要使用它们来初始化或退出,或者说注册以及后来的注销。 

当你用module_init()为一个模块注册了之后,在你使用insmod这个命令去安装的时候,module_init()注册的函数将会被执行。而当你用rmmod这个命令去卸载一个模块的时候,module_exit()注册的函数将会被执行。module_init()被称为驱动程序的初始化入口(driver initialization entry point)。 

怎么样演示以上代码的运行呢?没错,你需要一个Makefile。

1 # To build modules outside of the kernel tree, we run "make"
   2 # in the kernel source tree; the Makefile these then includes this
   3 # Makefile once again.
    4 # This conditional selects whether we are being included from the
    5 # kernel Makefile or not.
    6 ifeq ($(KERNELRELEASE),)
   7
    8     # Assume the source tree is where the running kernel was built
    9     # You should set KERNELDIR in the environment if it's elsewhere
    10     KERNELDIR ?= /lib/modules/$(shell uname -r)/build
   11     # The current directory is passed to sub-makes as argument
   12     PWD := $(shell pwd)
    13
    14 modules:
    15         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    16
    17 modules_install:
    18         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    19
    20 clean:
    21         rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
    22
    23 .PHONY: modules modules_install clean
    24
    25 else
    26     # called from kernel build system: just declare what our modules are
    27     obj-m := hello.o
    28 endif
 

在lwn.net上可以找到这个例子,你可以把以上两个文件放在你的某个目录下,然后执行make,也许你不一定能成功,因为Linux Kernel 2.6要求你编译模块之前,必须先在内核源代码目录下执行make,换言之,你必须先配置过内核,执行过make,然后才能make你自己的模块。原因就不细说了,你按着要求的这么去做就行了。在内核顶层目录make过之后,你就可以在你当前放置Makefile的目录下执行make了。make之后你就应该看到一个叫做hello.ko的文件生成了,恭喜你,这就是你将要测试的模块。

执行命令,

#insmod hello.ko  

同时在另一个窗口,用命令tail -f /var/log/messages察看日志文件,你会看到Hello world被打印了出来。再执行命令,

#rmmod hello.ko  

此时,在另一窗口你会看到Goodbye,cruel world!被打印了出来。 

到这里,我该恭喜你,因为你已经能够编写Linux内核模块了。这种感觉很美妙,不是吗?你可以嘲笑秦皇汉武略输文采唐宗宋祖稍逊风骚,还可以嘲笑一代天骄成吉思汗只识弯弓射大雕了。是的,阿娇姐姐告诉我们,只要我喜欢,还有什么不可以。 

       日后我们会看到,2.6内核中,每个模块都是以module_init开始,以module_exit结束。对大多数人来说没有必要知道这是为什么,记住就可以了,对大多数人来说,这就像是1+1为什么等于2一样,就像是两点之间最短的是直线,不需要证明,如果一定要证明两点之间直线最短,可以扔一块骨头在B点,让一条狗从A点出发,你会发现狗走的是直线,是的,狗都知道,咱还能不知道吗?

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 流浓鼻涕怎么办速效办法 鼻涕又浓又黄绿怎么办 玉露已经徒长了怎么办 多肉长出了多头怎么办 多肉已经徒长了怎么办 脖子抻筋了 很疼怎么办 声带肥大造成说话声音沙哑怎么办 轻微的骨性龅牙怎么办 19岁没了晨勃怎么办 早上晨勃消失了怎么办 阴茎勃而不坚怎么办 一个月婴儿痰多怎么办 孕妇咳绿色浓痰怎么办 买的戒指大了怎么办 孩子鞋子买大了怎么办 鞋子不大但掉跟怎么办 鞋子长了一码怎么办 新鞋有点顶脚怎么办 宝宝鞋子买小了怎么办 鞋子买的小了怎么办 粉底液颜色偏黄怎么办 腿长的不直怎么办 多梦睡眠质量差怎么办 颈椎病引起的脑供血不足怎么办 骨头轻微的骨裂怎么办 怀孕六个月不想要怎么办 脚面一用力筋疼怎么办 肚子经常饿的响怎么办 一宿没睡第二天怎么办 婚姻走不下去了 怎么办 作业好多怎么办想哭了 熬夜后恶心想吐怎么办 脸上长了小肉瘤怎么办 6sp电池不耐用怎么办 小孩个子长得慢怎么办 4岁儿童身高偏矮怎么办 13孩子身高偏矮怎么办 9岁儿童身高偏矮怎么办 3岁宝宝个子偏矮怎么办 6岁宝宝个子偏矮怎么办 5岁宝宝个子偏矮怎么办