linux模块编译
2015-06-05 18:22
363 查看
内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),我们简称为模块。模块具有以下特点:
1 模块本身不被编译入内核映像,从而控制了内核的大小
2 模块一旦被加载,它就和内核中的其他部分一样
一、 什么是模块
模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。
首先编写hello.c文件
#include<linux/init.h>
#include<linux/module.h>
//模块许可证声明
MODULE_LICENSE("Dual BSD/GPL");
//模块加载函数
static int hello_init(void)
{
printk("Imagination is more important than knowledge !\n");
return 0;
}
//模块卸载函数
static void hello_exit(void)
{
printk("hello world exit ! Congratulations!\n");
}
//这是驱动程序初始化的入口点。对于内置模块,内核在引导时调用该入口 //点;
对于可加载模块则在该模块插入内核时才调用。
module_init(hello_init);
//对于可加载模块,内核在此处调用module_cleanup()函数,而对于内置 //的模块,
它什么都不做。
module_exit(hello_exit);
//可选
MODULE_AUTHOR("IMAGINECUP");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("A simplest module");
编写Makefile文件
obj-m +=hello.o #产生hello模块的目标文件
CURRENT_PATH :=$(shell pwd) #模块所在的当前路径
LINUX_KERNEL :=$(shell uname -r) #Linux内核源代码的当前版本
LINUX_KERNEL_PATH :=/usr/src/linux-headers-$(LINUX_KERNEL) #Linux 内核源代码的绝对路径
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模 块
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理
完成上述两个步骤,然后再模块所在路径运行make命令,即生成模块目标文件(hello.ko)
然后你可以运行insmod命令来加载模块,当模块加载后你可以通过lsmod查看模块是否被加载进去。rmmod命令用来卸载模块,dmesg命令可以查看模块执行的结果.
从上面的编译中我可以看到。已经有一个hello.ko生成了。这就是我们的模块了。现在我们就可以来加载了。
首先在终端输入:sudo insmod hello.ko
现在我们来看看我们的模块加载成功没有呢?
在终端输入:dmesg | tail -12 这是查看内核输出信息的意思。tail
-12 显示最后12条;
也可以用lsmod|grep hello查看刚才安装的模块,显示的就是.ko前面的名称
知识点:
内核符号表:
内存地址 符号名 [所属模块]
在模块编程中,可以根据符号名从这个文件中检索出其对应的地址,然后直接访问该地址从而获得内核数据。第三列“所属模块”指符号所在的模块名,对于从内核这一母模块移出的符号,这一列为空。
可通过/proc/kallsyms查看模块输出的内核符号
模块依赖
如前所述,内核符号表记录了所有模块可以访问的符号及相应的地址。当一个新的模块被装入内核后,它所申明的某些符号就会被登记到这个表中,而这些符号可能被其他模块所引用,这就引出了模块依赖这个问题。
一个模块A引用另一个模块B所移出的符号,我们就说模块B被模块A引用,或者说模块A依赖模块B。如果要链接模块A,必须先链接模块B。这种模块间相互依赖的关系就叫模块依赖。
模块引用计数器
为 了确保模块安全地卸载,每个模块都有一个引用计数器。当执行模块所涉及的操作时就递增计数器,在操作结束时就递减这个计数器;另外,当模块B被模块A引用 时,模块B的引用计数就递增,引用结束,计数器递减。什么时候可以卸载这个模块?当然只有这个计数器值为0的时候,例如,当一个文件系统还被安装在系统上 时就不能将其卸载,当这个文件系统不再被使用时,引用计数器就为0,于是可以卸载。
1 模块本身不被编译入内核映像,从而控制了内核的大小
2 模块一旦被加载,它就和内核中的其他部分一样
一、 什么是模块
模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。
首先编写hello.c文件
#include<linux/init.h>
#include<linux/module.h>
//模块许可证声明
MODULE_LICENSE("Dual BSD/GPL");
//模块加载函数
static int hello_init(void)
{
printk("Imagination is more important than knowledge !\n");
return 0;
}
//模块卸载函数
static void hello_exit(void)
{
printk("hello world exit ! Congratulations!\n");
}
//这是驱动程序初始化的入口点。对于内置模块,内核在引导时调用该入口 //点;
对于可加载模块则在该模块插入内核时才调用。
module_init(hello_init);
//对于可加载模块,内核在此处调用module_cleanup()函数,而对于内置 //的模块,
它什么都不做。
module_exit(hello_exit);
//可选
MODULE_AUTHOR("IMAGINECUP");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("A simplest module");
编写Makefile文件
obj-m +=hello.o #产生hello模块的目标文件
CURRENT_PATH :=$(shell pwd) #模块所在的当前路径
LINUX_KERNEL :=$(shell uname -r) #Linux内核源代码的当前版本
LINUX_KERNEL_PATH :=/usr/src/linux-headers-$(LINUX_KERNEL) #Linux 内核源代码的绝对路径
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模 块
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理
完成上述两个步骤,然后再模块所在路径运行make命令,即生成模块目标文件(hello.ko)
然后你可以运行insmod命令来加载模块,当模块加载后你可以通过lsmod查看模块是否被加载进去。rmmod命令用来卸载模块,dmesg命令可以查看模块执行的结果.
从上面的编译中我可以看到。已经有一个hello.ko生成了。这就是我们的模块了。现在我们就可以来加载了。
首先在终端输入:sudo insmod hello.ko
现在我们来看看我们的模块加载成功没有呢?
在终端输入:dmesg | tail -12 这是查看内核输出信息的意思。tail
-12 显示最后12条;
也可以用lsmod|grep hello查看刚才安装的模块,显示的就是.ko前面的名称
知识点:
内核符号表:
内存地址 符号名 [所属模块]
在模块编程中,可以根据符号名从这个文件中检索出其对应的地址,然后直接访问该地址从而获得内核数据。第三列“所属模块”指符号所在的模块名,对于从内核这一母模块移出的符号,这一列为空。
可通过/proc/kallsyms查看模块输出的内核符号
模块依赖
如前所述,内核符号表记录了所有模块可以访问的符号及相应的地址。当一个新的模块被装入内核后,它所申明的某些符号就会被登记到这个表中,而这些符号可能被其他模块所引用,这就引出了模块依赖这个问题。
一个模块A引用另一个模块B所移出的符号,我们就说模块B被模块A引用,或者说模块A依赖模块B。如果要链接模块A,必须先链接模块B。这种模块间相互依赖的关系就叫模块依赖。
模块引用计数器
为 了确保模块安全地卸载,每个模块都有一个引用计数器。当执行模块所涉及的操作时就递增计数器,在操作结束时就递减这个计数器;另外,当模块B被模块A引用 时,模块B的引用计数就递增,引用结束,计数器递减。什么时候可以卸载这个模块?当然只有这个计数器值为0的时候,例如,当一个文件系统还被安装在系统上 时就不能将其卸载,当这个文件系统不再被使用时,引用计数器就为0,于是可以卸载。
相关文章推荐
- LINUX 查看硬件配置命令
- linux(以ubuntu为例)下Android利用ant自动编译、修改配置文件、批量多渠道,打包生成apk文件
- Linux系统抓包命令tcpdump使用实例
- Linux下启动mysql
- 在windows上通过ssh远程链接linux服务器[转]
- [linux] scp无密码拷贝
- 在Linux系统中安装使用恶意软件扫描工具及杀毒引擎的教程
- linux下不同服务器间数据传输(rcp,scp,rsync,ftp,sftp,lftp,wget,curl)
- 3-Linux基本命令
- 对 Linux 新手非常有用的 20 个命令
- DayDayUP_Linux运维学习_VMware克隆后找不到eth0
- Linux下内核socket优化项
- DayDayUP_Linux运维学习_查看linux版本的方法2
- busybox号称linux下的瑞士小军刀
- Linux下使用Eclipse开发C\C++
- CentOS iso下载
- Linux/Windows设置完成端口的区间
- rsync命令详解
- Linux守护进程的编程实现
- linux回到上次目录与历史命令查找快捷方式