读Kernel感悟-kbuild系统-编译到内核和编译成模块的区别
2009-05-21 17:05
429 查看
代码编译到内核和编译成模块在代码中有什么区别呢?
从模块的代码中看是一样的。入口函数都是module_init(fun),但是代码中的条件编译会使宏module_init()在编译到内核和编译成模块的情况下替换成不同的代码。
include/linux/init.h中可知
#ifndef MODULE
...
#define module_init(x) __initcall(x);
...
#else /* MODULE */
...
/* Each module must use one module_init(), or one no_module_init */
#define module_init(initfn) /
static inline initcall_t __inittest(void) /
{ return initfn; } /
int init_module(void) __attribute__((alias(#initfn)));
...
#endif
当代码编译成模块时,会定义MODULE宏,否则不会。因为在/usr/src/linux/Makefile中可以看到
336 MODFLAGS = -DMODULE
337 CFLAGS_MODULE = $(MODFLAGS)
338 AFLAGS_MODULE = $(MODFLAGS)
这两个变量又被export成为全局变量。所以可以知道,在编译成模块时,会有MODULE这个宏。
由以下代码可以知道
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn)
085 #define __define_initcall(level,fn) /
086 static initcall_t __initcall_##fn __attribute_used__ /
087 __attribute__((__section__(".initcall" level ".init"))) = fn
前者实际上是编译入内核中的.initcall6.init 这个section
而在
arch/i386/kernel/vmlinux.lds.S中可以知道:
083 __initcall_start = .;
084 .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
085 *(.initcall1.init)
086 *(.initcall2.init)
087 *(.initcall3.init)
088 *(.initcall4.init)
089 *(.initcall5.init)
090 *(.initcall6.init)
091 *(.initcall7.init)
092 }
093 __initcall_end = .;
arch/i386/kernel/vmlinux.lds.S
.initcall6.init是.initcall.init的一部分
执行顺序:
start_kernel->rest_init
系统启动后在rest_init中会创建init内核线程
init->do_basic_setup->do_initcalls
do_initcalls中会把.initcall.init中的函数依次执行一遍
for (call = __initcall_start; call < __initcall_end; call++) {
...
(*call)();
...
}
于是执行了module_init(fn)函数
转载自:http://www.top-e.org/jiaoshi/html/?240.html
从模块的代码中看是一样的。入口函数都是module_init(fun),但是代码中的条件编译会使宏module_init()在编译到内核和编译成模块的情况下替换成不同的代码。
include/linux/init.h中可知
#ifndef MODULE
...
#define module_init(x) __initcall(x);
...
#else /* MODULE */
...
/* Each module must use one module_init(), or one no_module_init */
#define module_init(initfn) /
static inline initcall_t __inittest(void) /
{ return initfn; } /
int init_module(void) __attribute__((alias(#initfn)));
...
#endif
当代码编译成模块时,会定义MODULE宏,否则不会。因为在/usr/src/linux/Makefile中可以看到
336 MODFLAGS = -DMODULE
337 CFLAGS_MODULE = $(MODFLAGS)
338 AFLAGS_MODULE = $(MODFLAGS)
这两个变量又被export成为全局变量。所以可以知道,在编译成模块时,会有MODULE这个宏。
由以下代码可以知道
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn)
085 #define __define_initcall(level,fn) /
086 static initcall_t __initcall_##fn __attribute_used__ /
087 __attribute__((__section__(".initcall" level ".init"))) = fn
前者实际上是编译入内核中的.initcall6.init 这个section
而在
arch/i386/kernel/vmlinux.lds.S中可以知道:
083 __initcall_start = .;
084 .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
085 *(.initcall1.init)
086 *(.initcall2.init)
087 *(.initcall3.init)
088 *(.initcall4.init)
089 *(.initcall5.init)
090 *(.initcall6.init)
091 *(.initcall7.init)
092 }
093 __initcall_end = .;
arch/i386/kernel/vmlinux.lds.S
.initcall6.init是.initcall.init的一部分
执行顺序:
start_kernel->rest_init
系统启动后在rest_init中会创建init内核线程
init->do_basic_setup->do_initcalls
do_initcalls中会把.initcall.init中的函数依次执行一遍
for (call = __initcall_start; call < __initcall_end; call++) {
...
(*call)();
...
}
于是执行了module_init(fn)函数
转载自:http://www.top-e.org/jiaoshi/html/?240.html
相关文章推荐
- 读Kernel感悟-kbuild系统-内核模块的编译
- 读Kernel感悟-kbuild系统-内核模块的编译
- kbuild系统-编译到内核和编译成模块的区别
- kbuild系统-编译到内核和编译成模块的区别
- Linux kernel 分析之十三:kbuild系统-编译到内核和编译成模块的区别
- kbuild系统-内核模块的编译
- Linux kernel 分析之十二:kbuild系统-内核模块的编译
- 老司机带你探索内核编译系统--kbuild
- linux命令:kernel内核编译、装载模块管理modprobe/screen
- 利用模块添加系统调用(不重新编译内核)
- 利用模块添加系统调用(不重新编译内核)
- 编译内核模块的Makefile中的($(KERNELRELEASE)
- kernel 内核模块编译
- [Kernel] Linux 4.10.0+ 下编译安装内核模块(Hello World为例)
- 编译时向内核添加新设备 模块的方式动态的将驱动加入内核,但这种方式加入的驱动程序,当系统重新启动时, 还需要重新用模块的方式进行插入,如果是系统内常用的设备驱动采用这种方式进行加载, 就会很不方便。
- 驱动编译进内核或编译模块的区别
- Android Goldfish内核编译 + eCryptfs文件加解密系统的内核模块配置
- 《Linux kernel panic》内核模块空指针导致系统crash
- linux内核编译及系统裁减(sysctl 内核模块管理 screen 生成initrd cron
- Android中kernel内核模块编译执行