Linux Module详解

来源:互联网 发布:windows刷mac os 编辑:程序博客网 时间:2024/05/23 11:46

Module的一个例子:
创建两个文件

hello.c文件

#include <linux/init.h>#include <linux/module.h>MODULE_LICENSE("Dual BSD/GPL");static int hello_init(void){    printk(KERN_ALERT "Hello, world\n");    return 0;}static void hello_exit(void){    printk(KERN_ALERT "Goodbye, cruel world\n");}module_init(hello_init);module_exit(hello_exit);

Makefile可以参考如下

obj-m += hello.oKERNEL ?= /lib/modules/$(shell uname -r)/buildall:    make -C $(KERNEL) M=$(PWD) modulesclean:    make -C $(KERNEL) M=$(PWD) clean

把hello.c文件和上面的Makefile文件放到同一个目录下
#make命令编译
#su获取root权限
#insmod hello.ko
之后就可以在kernel log里看到输出”Hello, world”,
也可以在#cat /proc/modules 来确认是否已经加到内核
#rummod hello.ko 就可以在kernel log看到输出”Goodbye, cruel world”

module_init宏被定义在kernel/include/linux/init.h文件里
根据是否定义了MODULE,可以分成两个。那MODULE到底有没有定义呢?ARM上面的看来是没有编译,那MODULE宏具体有什么作用呢?后面再说。
MODULE宏这里是有定义的!!
先来看看在MODULE宏没有定义的时候,module_init在kernel/include/linux/init.h文件里的定义形式。

#define module_init(x) __initcall(x);#define __initcall(fn) device_initcall(fn);#define device_initcall(fn) __define_initcall(fn, 6);#define __define_initcall(fn, id) \static initcall_t __initcall_##fn##id __used \__attribute__((__section__(".initcall" #id ".init"))) = fn

下面来讲__define_initcall的定义,都代表什么。
static initcall_t 这里 initcall_t的定义是 : typedef int (*initcall_t)(void)
表示后面跟的是一个返回值是int型,且没有参数的一个函数的指针。举一个例子就是mdss_fb_init函数,定义就是
int __init mdss_fb_init(void) { } == 前面__int代表什么呢?后面再说。但返回值是int以及没有参数,都跟上面说明符合,
可以查看一下其他的module_init定义的函数,都是一样的。
上面大概的意思就是定义一个指向函数的指针,以mdss_fb_init为例,就是定义了__initcall_mdss_fb_init6,把mdss_fb_init函数的指针赋给它,
并把__initcall_mdss_fb_init6放到在vmlinux.lds文件里边指定的.initcall6.init区间里边。
下面是生成的vmlinux.lds文件里边的一段。

 .init.data : {  *(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; *(.meminit.rodata) . = ALIGN(8); __cpu_method_of_table = .; *(__cpu_method_of_table) __cpu_method_of_table_end = .; . = ALIGN(8); __clksrc_of_table = .; *(__clksrc_of_table) *(__clksrc_of_table_end) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .; . = ALIGN(8); __irqchip_begin = .; *(__irqchip_of_table) *(__irqchip_of_end)  . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;  __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;  __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;  __compat_exports_start = .; *(.exportcompat.init) __compat_exports_end = .;  __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;  . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info) }

在生成的System.map里边也可以证明如上所说的说明是正确的。
c115928c T __initcall6_start
……
c11594cc t __initcall_mdss_fb_init6
…….

这里再介绍一下像int __init mdss_fb_init(void) { }这种用包含在module_init里边的函数定义,函数名字前面加上__init到底什么意思。
__init的定义是 #define __init __section(.init.text) __cold notrace。
在定义的init.h文件里边,有对__init的说明如下。

/* These macros are used to mark some functions or  * initialized data (doesn't apply to uninitialized data) * as `initialization' functions. The kernel can take this * as hint that the function is used only during the initialization * phase and free up used memory resources after * * Usage: * For functions: *  * You should add __init immediately before the function name, like: * * static void __init initme(int x, int y) * { *    extern int z; z = x * y; * } * * If the function has a prototype somewhere, you can also add * __init between closing brace of the prototype and semicolon: * * extern int initialize_foobar_device(int, int, int) __init; * * For initialized data: * You should insert __initdata between the variable name and equal * sign followed by value, e.g.: * * static int init_variable __initdata = 0; * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; * * Don't forget to initialize data not at file scope, i.e. within a function, * as gcc otherwise puts the data into the bss section and not into the init * section. *  * Also note, that this data cannot be "const". *//* These are for everybody (although not all archs will actually   discard it in modules) */#define __init __section(.init.text) __cold notrace //__cold 和notrace具体干嘛的?#define __initdata __section(.init.data)#define __initconst __constsection(.init.rodata)#define __exitdata __section(.exit.data)#define __exit_call __used __section(.exitcall.exit)

就是说如果某个函数或者变量只在初始化的时候用到,后面可以被清理掉也没有关系的话,就最好定义成上面的一种,以便释放更多空间。
这里具体怎么释放加了上面定义的的函数和变量? 应该是放到了特定区域里边一起释放,具体后面再说。
还有这种__init定义方式需要注意,不要用在函数里边的

__cold表示什么,代码里边有说明,但需要具体解释

/* Mark functions as cold. gcc will assume any path leading to a call
to them will be unlikely. This means a lot of manual unlikely()s
are unnecessary now for any paths leading to the usual suspects
like BUG(), printk(), panic() etc. [but let’s keep them for now for
older compilers]

Early snapshots of gcc 4.3 don’t support this and we can’t detect this
in the preprocessor, but we can live with this because they’re unreleased.
Maketime probing would be overkill here.

gcc also has a attribute((hot)) to move hot functions into
a special section, but I don’t see any sense in this right now in
the kernel context */

#########各种初始化函数的初始化顺序,可以参考下面的定义
#define pure_initcall(fn) __define_initcall(fn, 0)#define core_initcall(fn) __define_initcall(fn, 1)#define core_initcall_sync(fn) __define_initcall(fn, 1s)#define postcore_initcall(fn) __define_initcall(fn, 2)#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)#define arch_initcall(fn) __define_initcall(fn, 3)#define arch_initcall_sync(fn) __define_initcall(fn, 3s)#define subsys_initcall(fn) __define_initcall(fn, 4)#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)#define fs_initcall(fn) __define_initcall(fn, 5)#define fs_initcall_sync(fn) __define_initcall(fn, 5s)#define rootfs_initcall(fn) __define_initcall(fn, rootfs)#define device_initcall(fn) __define_initcall(fn, 6)#define device_initcall_sync(fn) __define_initcall(fn, 6s)#define late_initcall(fn) __define_initcall(fn, 7)#define late_initcall_sync(fn) __define_initcall(fn, 7s)
0 0