内核模块与应用程序的区别
-
内核模块是在内核空间运行,而应用程序是在用户空间运行。这个概念是操作系统理论的基础。
-
内核模块是内核的功能扩展。一个驱动在执行前会进行两种任务:模块中一些函数作为系统调用的一部分执行,另外一些负责中断处理。
-
内核模块编程和应用程序编程最大的不同是并发问题。大部分应用程序(除多线程的应用程序)是典型地是顺序运行的,不会出现错误。然而内核代码没有运行在这样的简单世界中,编写内核代码时,必须得细心考虑并发问题,以防止内核中多路径对共享内存同时访问和操作所造成的系统不稳定甚至是错误,一旦出错这将会很难跟踪和定位。
-
与应用程序拥有很大的堆栈区相比,内核空间的堆栈区是很小的,整个内核空间甚至可能只有
4096
字节空间大小的栈。所以在内核编程以及编写驱动时,声明巨大的Auto
变量和递归调用等一切占用大量堆栈空间操作都是不好的。说不定在何时直接stackflow
(堆栈溢出)。
🤔不确定的点:内核是栈比较小,还是堆栈都比较小
内核对栈大小的定义:
//include/asm-i386/thread_info.h THREAD_SIZE
#ifdef CONFIG_4KSTACKS
#define THREAD_SIZE (4096)
#else
#define THREAD_SIZE (8192)
#endif
//内核配置的时候,有一个4K内核栈的选项,如果选上了,内核栈为4K;如果没有选上,内核栈是8K。
内核栈的小,推使我们去使用动态内存,也就是堆空间。
-
内核编程相比较应用程序编程更应该小心。应用程序的段错误最多会导致这一个程序的死掉(对系统无害),但是内核程序的内存的错误使用会极大可能的破坏系统,导致系统无法正常工作(系统崩溃)。
-
内核代码不能做浮点算术。使能浮点将要求内核在每次进出内核空间的时候保存和恢复浮点处理器的状态——至少,在某些体系上在这种情况下,内核代码真的没有必要包含浮点,额外的负担不值得。
-
应用程序可以调用C库,而内核程序由于在C库的下层,导致C库不能使用,但是在内核中会有类似的函数可以调用。
因为没有库连接到模块中, 源文件不应当包含通常的头文件, <stdarg.h>
和非常特殊的情况是仅有的例外. 只有实际上是内核的一部分的函数才可以在内核模块里使用. 内核相关的任何东西都在头文件里声明, 这些头文件在你已建立和配置的内核源码树里; 大部分相关的头文件位于 include/linux
和 include/asm
, 但是别的 include 的子目录已经添加
到关联特定内核子系统的材料里了.
可以通过下面的命令查看:
$ cat /proc/kallsyms | grep printk
...
0000000000000000 T printk
0000000000000000 T printk_emit
...
所有内核中可以用的函数/
符号都在/proc/kallsyms
,换句话说,你不能使用这里之外的函数/
符号。
🤔再者其次,其中的 T 代表什么意思?
- 应用程序的入口是
main()
函数,而内核驱动的入口是init_module()
,出口是exit_module()
。