内核程序,makefile分析(转自CSDN)

内核模块----

linux内核的整体结构庞大,其中包含的组件也很多,如何使用需要的组件?

1--把所有的组件都编译进内核文件,即zImage,bzImage,但这样会导致两个问题:一是生产的内核文件过大,二是,如果要添加或删除某个组件要重新编译整个内核。

内核模块机制---提供一种机制能让内核文件(zImage,bzImage)本身并不包含某组件,而是在该组件需要被使用的时候,动态的添加到正在运行的内核中。

内核模块特点--

模块本身并不被编译进内核文件,可在内核运行期间动态的安装或卸载。

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("DAVID");
MODULE_DESCRIPTION("Hello world module");
static int __init hello_init(void)
{
    printk(KERN_ERR "hello world!\n");
    return 0;
}
static void __exit hello_exit(void)
{
    printk(KERN_EMERG "hello exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);


#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("DAVID");
MODULE_DESCRIPTION("Hello world module");
static int __init hello_init(void)
{
    printk(KERN_ERR "hello world!\n");
    return 0;
}
static void __exit hello_exit(void)
{
    printk(KERN_EMERG "hello exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);


程序结构---

1--模块加载函数


安装模块时被系统自动调用的函数,通过module_init宏来指定。


2--模块卸载函数


卸载模块时被系统自动调用的函数。通过module_exit宏来指定。



模块的编译---

在linux2.6编译内核模块,通常使用makefile

1--内核模块由一个源文件构成,编写makefile

ifneq ($(KERNELRELEASE),)若变量和空不相等,第一次执行时变量等于空故执行else
obj-m :=hello.o编译出来的内核模块的名字。若想不一样,需要修改。
else
KDIR:= /lib/modules/2.6.18-53.el5/build编译内核模块需要依赖内核源代码,需要给出其路径
all:
    make -C $(KDIR) M=$(PWD) modules   -C表示进入内核源代码目录,$(PWD)表示,模块在当前目录下,总体来说,是使用目录下的内核源代码来编译当前目录下的模块,当第二次编译使用makefile时,KERNELRELEASE就有值了,是内核版本号。

clean:
    rm -f *.ko *.o *.mod.o *.mod.c .symvers
endif


2--内核模块由多个源文件构成,编写makefile

ifneq ($(KERNELRELEASE),)
obj-m := hello.o

hello-objs :=main.o add.o
else
    
KDIR := /lib/modules/2.6.18-53.el5/build
all:
    make -C $(KDIR) M=$(PWD) modules
clean:
    rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif


加载---insmod

卸载---rmmod

查看---lsmod

加载----modprobe

modprobe会根据文件/lib/modules/<$version>/modules.dep

来查看要加载的模块,看它是否还依赖于其它模块,若是,会先加载它们到内核。


模块可选信息---

1--许可证申明

宏MODULE_LICENSE用来告知内核,该模块带有一个许可证(GPL,GPLv2等)。

2---MODULE_AUTHER()作者

3--MODULE_DESCRIPTION()描述

4--MODULE_VERSION()版本

5--MODULE_ALIAS()别名

6--模块参数

module_param(name,type,perm)

name-参数名字

type-参数类型

perm--模块参数的访问权限。常见值:

S_IRUGO:任何用户都对/sys/module中出现该参数具有读权限。

S_IWUSR::允许root用户修改/sys/module中出现的该参数。

如:int a=3; char *st;

module_param(a,int,S_IRUGO);

module_param(st,charp,S_IRUGO);

通过宏module_param指定模块参数,模块参数用于在加载模块时传递参数给模块。


内核符号导出--

/proc/kallsyms记录了内核中所有导出符号的名字和地址。

EXPORT_SYMBOL(sum);当在一个模块中使用另外一个模块中的符号,比如函数,需要在被调用函数里导出函数名,调用函数才能使用。

EXPORT_SYMBOL(符号名)

EXPORT_SYMBOL_GPL(符号名)只能用于包含GPL许可证的模块。


内核打印---

在<linux/kernel.h>中定义了8种记录级别。按照优先级递减的顺序分别是:

KERN_EMERG            0

KERN_ALERT              1

KERN_CRIT                2

KERN_ERR                    3

KERN_EMERG            4

KERN_WARNING        5

KERN_NOTICE          6

KERN_INFO            7

KERN_DEBUG          8

没有指定优先级的printk默认使用

DEFAULT_MESSAGE_LOGLEVEL它是一个在kernel/printk.c中定义的整数。

在2.6.29内核中

#define   DEFAULT_MESSAGE_LOGLEVEL 5


控制台优先级配置---纯字符界面

/proc/sys/kernel/printk

6 4 1 7

Console_loglevel

Default_message_loglevel

Minimum_console_level

Default_console_loglevel



你可能感兴趣的:(内核程序,makefile分析(转自CSDN))