模块是如何加载到内核的


要支持模块的动态加载,卸载, 在编译内核时要注意: “Lodable Module Support" 中的相应选项要选上. 比如要支持加载模块, 应该选上Enable loadable module support; 要支持卸载模块, 要选上Module unloading ; 要支持强制卸载模块, 要选上Forced module unloading!

1, When the kernel needs a feature that is not resident in the kernel, the kernel module daemon kmod (In earlier versions of linux, this was known as kerneld) execs modprobe to load the module in. modprobe is passed a string in one of two forms:

  • A module name like softdog or ppp.

  • A more generic identifier like char-major-10-30

传递给mdoprobe的参数为模块名时, 不需要加.ko的扩展名. 若传递给modprobe的是通用标志符, 那么modprobe通过查看etc/modprobe.conf知道通用标志符对应的模块名.

modprobe.conf文件是特定于发行版的, 比如我的Ubuntu中, modprobe查看/etc/modprobe.d/aliases来将通用标志符转化为模块名.

2, 注意模块也存在依赖性问题: 比如你要加载msdos.ko, 需要先加载fat.ko. modprobe查看/lib/module/version/modules.dep得知模块的依赖关系. (version = uname -r). moules.dep由$ depmod -a 命令创建.

依赖其他模块的模块称为: "stacking modules"

3, 知道了依赖关系之后, mprobe先加载prerequisites模块, 再加载模块自身. 实际上, modprobe是通过调用insmod来加载这些模块的!

有两种加载模块的方法, 以刚才的msdos.ko为例子:

$ insmod /lib/modules/version/kernel/fs/fat/fat.ko$ insmod /lib/modules/version/kernel/fs/msdos/msdos.ko

$ modprobe msdos

modprobe和insmod的区别:
1, modprobe知道内核模块默认的存在目录(/lib/modules/version/), 而insmod不知道.
2, 调用modprobe时, 只需给出模块名(不代,ko扩展), 而insmod需要给出完整路径和模块名.
3, modprobe自动解决依赖性. 而insmod需要指定加载内核的先后顺序.
4, 由于modprobe假设要加载的模块在默认目录, 那么若要加载在默认目录之外的模块, 就要调用insmod了.

发行版将modprobe, insmod, depmod打包到一起, 称之为Linux内核模块管理工具, 针对2.4或以前的内核, 该工具名为modutils, 2.6的为module-init-tools.

通过$ lsmod 可以看到加载到内核中的模块信息 也可以查看/proc/modules文件的内容. 实际上,lsmod读命令就是通过查看/proc/modules的内容来显示模块信息的.

卸载模块


使用 $ sudo rmmod mod_name 可以卸载模块. 但内核有时候认为卸载该模块是不安全的, 此时可以使用 $ sudo rmmod -f mod_name来强制卸载模块.

这里都是介绍的加载,卸载模块的命令, 至于模块加载,卸载的原理. 参考" 模块运行环境"

准备工作



模块可以加载到当前运行的内核中, 也可以加载到另一个未运行的内核. 这里暂时只考虑将模块加载到启动的内核中.

学习模块编程, 先要重新编译内核, 为什么要编译内核的? 原因有二:

1, 我们使用的Linux发行版中的内核针对kernel.org的官方内核添加了许多补丁, 提供的内核头文件并不完整, 内核API也可能被修改了, 要学习模块编程, 最好使用官方内核编译.

2, 发行版的内核中, 一般默认的CONFIG_MODVERSIONS被设置为y.  这样你在加载模块时会由于版本问题失败, 所以应该不设置CONFIG_MODVERSIONS.

参考内核模块编程之_初窥门径

模块程序组成


模块程序设计有点类似于应用程序设计: 起码模块程序中有entry point和exit point. 并且模块程序代码位于独立的文件中.

下面看看模块程序组成.

模块程序中至少要有两个函数: 一个初始化函数, 它在模块被加载到内核中的时候被调用, 一个退出函数(clean_up), 它在模块被卸载的时候被调用.

有两种方法定义上述的两个函数, 推荐用后面的定义方法!

int init_module(void)
{
 ...
}

void cleanup_module(void)
{
 ...
}

在2.3.13版之后的内核, 可以用下面的方法来定义它们:

static int hello_start(void)
{
 ...
}

static void hello_end(void)
{
 ...
}

module_init(hello_start);
module_exit(hello_end);

1, 初始化函数和退出函数的定义.
初始化函数和退出函数应该是这样的形式:

static int funname_init(void);     /* 模块被加载时被调用 */
static void funname_exit(void);  /* 模块被卸载时被调用 */

由于不向外输出这些函数, 一般给它们加上static限定符号.

2, module_init和module_exit宏
funname_init()通过module_init()被注册为模块的entry point. 同样地, funname_exit()通过module_exit()宏被注册为模块的exit point. 注意: 如果文件被编译到静态内核映像中, 退出函数不会被执行. 这些宏扩展必须位于相应函数定义之后!

3, 版权信息
从2.4版的内核起, 可以使用一些宏来声明模块的版权信息:

MODULE_LICENSE()宏:
括号中的内容可以是下面的几种形式:

"GPL"                     [GNU Public License v2 or later]"GPL v2"                    [GNU Public License v2]"GPL and additional rights" [GNU Public License v2 rights and more]"Dual BSD/GPL"      [GNU Public License v2 or BSD license choice]"Dual MPL/GPL"      [GNU Public License v2 or Mozilla license choice]"Proprietary"      [Non free products]

如果是MODULE_LICENSE("Proprietary"), 那么你所编写的模块不是免费的, 内核社区将其视为"污染"了内核, 不会理会相关的bug report, 而且, 不遵循GPL的模块无法调用只针对GPL的符号(参考"输出符号"的内容).

如果声明双重版权, 那么在Linux上, 它与声明为GPL的效果是一样的, 即Linux只在意GPL版权.

另外, MODULE_DESCRIPTION() 描述模块的功能; MODULE_AUTHOR()描述模块的作者;  and MODULE_SUPPORTED_DEVICE() 声明模块所支持设备的类型.

在内核源码树的/include/linux/module.h中定义版权宏. 这些宏一般位于文件结尾.

4, 包含头文件.
在模块程序开头需要包含头文件:

#include <linux/kernel.h> /* 若使用了优先级标志,需包含 */

#include <linux/init.h> /* 若使用了宏, 需包含 */

ldd3笔记_2_加载模块方法, 模块程序组成【ZT】相关推荐

  1. 未能加载指定的模块“\Neo4j-Management.psd1

    未能加载指定的模块"\Neo4j-Management.psd1 解决方案 方法一 增加环境变量PSScriptRoot = "D:\beforeInstalling\neo4j- ...

  2. 如何实现动态加载Javascript 文件模块

    前端开发中仅在需要时的时候加载 JavaScript 模块.这样可以提供很大的性能,比如:您有一个组件,例如复杂的视频播放器,它可以使用大量 js,并且该视频仅在用户单击它时才会启动. 那么在这种情况 ...

  3. 单步调试理解webpack里通过require加载nodejs原生模块实现原理

    在webpack和nodejs里,我们经常使用require函数加载原生模块或者开发人员自定义的模块. 原生模块的加载,比如: const path = require("path" ...

  4. 【Ubuntu】自动加载第三方ko模块

    有时候,我们需要让系统加载第三方的内核模块,但是重新编译内核显然太繁琐,我们可以使用某些手段来手动加载或者自动加载这些模块. 手动加载 直接执行以下指令即可 sudo insmod *.ko 或者将k ...

  5. 微信和支付宝扫码之后,需要加载各种业务模块:

    作者:王大帅 链接:https://www.zhihu.com/question/55761088/answer/158872594 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

  6. Feko加载电容方法学习笔记

    Feko加载电容方法学习笔记 文章目录 1. 初始模型 2.Port1加大电阻 3. 改变Port1电压值 4. 加载电容值 Feko软件可以加上匹配电路进行联合仿真,也可以加载电容,电感进行匹配,这 ...

  7. i.MX6系列加载华为ME901s-821模块使用PPP拨号上网

    i.MX6系列加载华为ME901s-821模块使用PPP拨号上网 PPP协议 内核中添加PPP协议支持 内核USB驱动支持 交叉编译PPP 拨号 PPP协议 PPP(点到点协议)是为在同等单元之间传输 ...

  8. aws ena模块加载_在AWS上全自动实时重新加载Spring Boot应用程序

    aws ena模块加载 在这篇文章中,我们将研究Spring Boot的最佳机密之一: Spring Boot DevTools . 尽管可以在本地计算机上进行测试,但在与生产环境尽可能相似的环境中开 ...

  9. GEE学习笔记 八十七:python版GEE动态加载地图方法(更新版)

    为了防控疫情,继续宅在家里--. 国内某些在国外受过高等教育的人竟然认为公开承认上图红色注释会引起某些麻烦. 在Google Earth Engine的python版API更新后,之前使用folium ...

最新文章

  1. spring @component的作用
  2. .net完整的图文验证
  3. linux中通常使用 键来终止命令运行,【单选题】Linux中通常使用( )键来终止命令运行A. Ctrl+c B. Ctrl+d C. Ctrl+k D. Ctrl+f...
  4. 写有效率的SQL查询(V)
  5. Image、Byte[]、Bitmap相互转换
  6. centos7 更新yum安装源
  7. Couldn't find leader offsets for Set([smt,0], [smt,1], [smt,2])
  8. linux 关机 日志,centos7 异常关机了,怎么查看系统的异常日志?
  9. Hystrix面试 - 基于 request cache 请求缓存技术优化批量商品数据查询接口
  10. 第一个MapReduce程序-------WordCount
  11. WCF学习 (三)深入认识WCF契约
  12. hg6201m怎么设置虚拟服务器,移动光猫HG6201M定期重启设置
  13. 浏览器的about:config清缓存及其他参数大全及其具体用途介绍
  14. 自建KMS激活服务器:CentOS安装vlmcsd搭建
  15. nas 微型计算机,商为家用的利器 希捷BS 2- Bay NAS
  16. unity 刷新layout_【Unity源码学习】Layout
  17. 淘宝客引流的两个高效渠道
  18. 用c语言交通信号灯论文,plc交通信号灯毕业论文.doc
  19. Tree-Shaking原理
  20. 中国农大博士计算机专业考试大纲,中国农业大学考博经验

热门文章

  1. Android 8.0 系统学习(6)---Linux内核接口要求
  2. android 系统(20)---背光灯
  3. 硬件平台选型(1)---SDM 660 VS SDM670
  4. 深度相机---(2)结构光深度测距
  5. 阿里 mysql cluster_MySQL Cluster集群安装及使用-阿里云开发者社区
  6. ios 与web服务器传值_中高级iOS大厂面试宝典,拿到offer率80%,金三银四将是你的新起点...
  7. 微商如何打印电子面单
  8. 毕业之后,这些年薪 50w+ 的 90 后程序员都经历了什么?纯水贴
  9. 常微分方程第三版_常微分方程:(第六章)非线性微分方程:5节
  10. 百试不爽的求爱技巧百试不爽的求爱技巧