Hello,Module 最简单的内核模块
2011-08-06 09:18
381 查看
第一个最简单的内核模块什么事都不做,仅在内核加载时打印 “ hello,kernel world ” ,在模块卸载时打印 “ goodbye,kernel
world” ,虽然什么事情也做不了,但这已经是一个可以加载如内核的简单模块了。
在新建hello文件夹下建立两个文件:
hello.c 内容如下:
备注:
1. 引入一些思考,__init __exit 的作用是什么? 以下是完整的宏定义:
#define __init __attribute__((__section__(".init.text") ) )
#define __exit __attribute__((__section__(".exit.text")) )
另外,数据部分同样包含以下两个宏。
#define __initdata __attribute__((__section__(".init.data")))
#define __exitdata __attribute__((__section__(".ext.data")))
以上四个宏将指定了函数或者数据需要被编译器指定的section位置(代码段,数据段,==)。
init.text和.init.data这两个section段将会在模块被加载后释放掉。
.exit.text.和.exit.data这两个section.段将会在模块被卸载后释放掉。
所以程序编写过程中可以把某些合适的数据和函数指定到这四个seciton,以达到节约内存的目的。
如果有另一个问题,什么是section? ,这将涉及到一些ELF文件格式和编译方面的知识,读者可以google之。
2.printk函数
内核空间不能使用标准函数库,为了获得内核的打印输出,我们可以使用printk函数,该函数由以下几个级别定义:
使用方法为: printk(级别 "Hello, world!/n");
未指定日志级别的 printk() 采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在 kernel/printk.c 中被定义为整数 4,即对应KERN_WARNING。
在 /proc/sys/kernel/printk 会显示4个数值(可由 echo 修改),分别表示当前控制台日志级别、未明确指定日志级别的默认消息日志级别、最小(最高)允许设置的控制台日志级别、引导时默认的日志级别。当 printk() 中的消息日志级别小于当前控制台日志级别时,printk 的信息(要有/n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过 /proc/kmsg (或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk
的信息也会追加到 /var/log/messages.log 中。
Makefile 内容如下:
备注:
如果内核模块由多个文件组成那应该怎么写这个Makefile呢? 答案是 : obj-m:=hello.o good.o xxx.o ...
在命令行执行
无错误的话将会生成hello.ko 模块,运行insmod工具把模块插入内核:
运行 rmmod工具将模块从内核卸载:
输入以下命令在终端中查看内核输出
如何可以看到以下输出,那恭喜你成功了!!
以上内容估计学习过内核开发的都很熟悉,介绍内核开发的书有ldd3 《Linux 设备驱动开发》第三版,此书已被翻译成中文,可在网上搜索下载。本文这里给出此书的下载链接:
http://ishare.iask.sina.com.cn/f/8189282.html
world” ,虽然什么事情也做不了,但这已经是一个可以加载如内核的简单模块了。
在新建hello文件夹下建立两个文件:
hello.c Makefile
hello.c 内容如下:
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); static int __init hello_init(void) //模块的入口,当此模块被加载的时候调用 { printk(KERN_INFO "hello , kernel world\n"); return 0; } static void __exit hello_exit(void) //模块的出口,当模块被卸载的时候调用 { printk(KERN_INFO " goodbye,kernel world\n "); } module_init(hello_init);//指定模块入口函数 module_exit(hello_exit);//指定模块出口函数 //一些基本的模块信息,可以通过 "modinfo 模块名" 查看 MODULE_AUTHOR("xxxx"); MODULE_DESCRIPTION("A simple Hello World Module"); MODULE_ALIAS("a simplest module");
备注:
1. 引入一些思考,__init __exit 的作用是什么? 以下是完整的宏定义:
#define __init __attribute__((__section__(".init.text") ) )
#define __exit __attribute__((__section__(".exit.text")) )
另外,数据部分同样包含以下两个宏。
#define __initdata __attribute__((__section__(".init.data")))
#define __exitdata __attribute__((__section__(".ext.data")))
以上四个宏将指定了函数或者数据需要被编译器指定的section位置(代码段,数据段,==)。
init.text和.init.data这两个section段将会在模块被加载后释放掉。
.exit.text.和.exit.data这两个section.段将会在模块被卸载后释放掉。
所以程序编写过程中可以把某些合适的数据和函数指定到这四个seciton,以达到节约内存的目的。
如果有另一个问题,什么是section? ,这将涉及到一些ELF文件格式和编译方面的知识,读者可以google之。
2.printk函数
内核空间不能使用标准函数库,为了获得内核的打印输出,我们可以使用printk函数,该函数由以下几个级别定义:
#define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ #define KERN_ERR "<3>" /* error conditions */ #define KERN_WARNING "<4>" /* warning conditions */ #define KERN_NOTICE "<5>" /* normal but significant */ #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */
使用方法为: printk(级别 "Hello, world!/n");
未指定日志级别的 printk() 采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在 kernel/printk.c 中被定义为整数 4,即对应KERN_WARNING。
在 /proc/sys/kernel/printk 会显示4个数值(可由 echo 修改),分别表示当前控制台日志级别、未明确指定日志级别的默认消息日志级别、最小(最高)允许设置的控制台日志级别、引导时默认的日志级别。当 printk() 中的消息日志级别小于当前控制台日志级别时,printk 的信息(要有/n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过 /proc/kmsg (或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk
的信息也会追加到 /var/log/messages.log 中。
Makefile 内容如下:
obj-m:=hello.o
备注:
如果内核模块由多个文件组成那应该怎么写这个Makefile呢? 答案是 : obj-m:=hello.o good.o xxx.o ...
在命令行执行
$ make -C /usr/src/linux M=`pwd` modules
无错误的话将会生成hello.ko 模块,运行insmod工具把模块插入内核:
# insmod hello.ko
运行 rmmod工具将模块从内核卸载:
# rmmod hello
输入以下命令在终端中查看内核输出
# dmesg | tail -10
如何可以看到以下输出,那恭喜你成功了!!
[ 2840.707373] hello,kernel world [ 3054.477649] goodbye,kernel world
以上内容估计学习过内核开发的都很熟悉,介绍内核开发的书有ldd3 《Linux 设备驱动开发》第三版,此书已被翻译成中文,可在网上搜索下载。本文这里给出此书的下载链接:
http://ishare.iask.sina.com.cn/f/8189282.html
相关文章推荐
- "hello world" 简单内核模块
- 内核模块学习--编译自己的第一个内核模块hello_module
- Linux 内核模块参数学习module_param
- Linux下hello.ko内核模块制作的全过程
- 我的第一个内核模块——Hello,kernel
- 一个简单的内核模块实现
- Apache模块开发/用C语言扩展apache(3:一个非常简单的apache module)
- 解剖Nginx·模块开发篇(3)ngx_http_hello_world_module 模块的基本函数实现
- 编写一个简单的内核模块
- Linux 最简单内核模块 Hello World 示例
- linux-2.6内核模块引用计数的实现(try_module_get和module_put)
- 简单实例讲解linux的module模块编译步骤
- hello内核模块编译的全过程
- GDB简单调试linux内核与模块的方法
- uboot 参数对应着内核模块的参数 module_param
- 我的第一个内核模块hello.c
- 使用module_param来向内核模块传递参数
- Linux 2.6.x 内核模块加载错误 “Invalid module format” 解决办法
- 最简单的helloworld模块编译加载(linux3.5内核源码树建立)
- hello.c内核模块编译 -- linux内核