linux中引入模块机制有什么好处

linux中引入模块机制的好处:1、应用程序在退出时,可以不管资源的释放或者其他的清除工作,但是模块的退出函数却必须仔细此撤销初始化函数所作的一切;2、该机制有助于缩短模块的开发周期,即注册和卸载都很灵活方便。

linux中引入模块机制有什么好处

本教程操作环境:linux7.3系统、Dell G3电脑。

Linux中引入模块机制有什么好处?

首先,模块是预先注册自己以便服务于将来的某个请求,然后他的初始化函数就立即结束。换句话说,模块初始化函数的任务就是为以后调用函数预先作准备。

好处:

1) 应用程序在退出时,可以不管资源的释放或者其他的清除工作,但是模块的退出函数却必须仔细此撤销初始化函数所作的一切。

2) 该机制有助于缩短模块的开发周期。即:注册和卸载都很灵活方便。

Linux模块机制浅析

Linux允许用户通过插入模块,实现干预内核的目的。一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析。

模块的Hello World!

我们通过创建一个简单的模块进行测试。首先是源文件main.c和Makefile。

florian@florian-pc:~/module$ cat main.c

#include#include static int __init init(void){    printk("Hi module!n");    return 0;} static void __exit exit(void){    printk("Bye module!n");} module_init(init);module_exit(exit);

其中init为模块入口函数,在模块加载时被调用执行,exit为模块出口函数,在模块卸载被调用执行。

florian@florian-pc:~/module$ cat Makefile

obj-m += main.o#generate the pathCURRENT_PATH:=$(shell pwd)#the current kernel version numberLINUX_KERNEL:=$(shell uname -r)#the absolute pathLINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)#complie objectall:    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules#cleanclean:    make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

其中,obj-m指定了目标文件的名称,文件名需要和源文件名相同(扩展名除外),以便于make自动推导。

然后使用make命令编译模块,得到模块文件main.ko。

florian@florian-pc:~/module$ make

make -C /usr/src/linux-headers-2.6.35-22-generic M=/home/florian/module modulesmake[1]: 正在进入目录 `/usr/src/linux-headers-2.6.35-22-generic'  Building modules, stage 2.  MODPOST 1 modulesmake[1]:正在离开目录 `/usr/src/linux-headers-2.6.35-22-generic'

使用insmod和rmmod命令对模块进行加载和卸载操作,并使用dmesg打印内核日志。

florian@florian-pc:~/module$ sudo insmod main.ko;dmesg | tail -1[31077.810049] Hi module!
florian@florian-pc:~/module$ sudo rmmod main.ko;dmesg | tail -1[31078.960442] Bye module!

通过内核日志信息,可以看出模块的入口函数和出口函数都被正确调用执行。

模块文件

使用readelf命令查看一下模块文件main.ko的信息。

florian@florian-pc:~/module$ readelf -h main.ko

ELF Header:  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  Class:                             ELF32  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              REL (Relocatable file)  Machine:                           Intel 80386  Version:                           0x1  Entry point address:               0x0  Start of program headers:          0 (bytes into file)  Start of section headers:          1120 (bytes into file)  Flags:                             0x0  Size of this header:               52 (bytes)  Size of program headers:           0 (bytes)  Number of program headers:         0  Size of section headers:           40 (bytes)  Number of section headers:         19  Section header string table index: 16

我们发现main.ko的文件类型为可重定位目标文件,这和一般的目标文件格式没有任何区别。我们知道,目标文件是不能直接执行的,它需要经过链接器的地址空间分配、符号解析和重定位的过程,转化为可执行文件才能执行。

那么,内核将main.ko加载后,是否对其进行了链接呢?

模块数据结构

有道小P 有道小P

有道小P,新一代AI全科学习助手,在学习中遇到任何问题都可以问我。

有道小P 64 查看详情 有道小P

首先,我们了解一下模块的内核数据结构。

linux3.5.2/kernel/module.h:220

struct module{    ……    /* Startup function. */    int (*init)(void);    ……    /* Destruction function. */    void (*exit)(void);    ……};

模块数据结构的init和exit函数指针记录了我们定义的模块入口函数和出口函数。

模块加载

模块加载由内核的系统调用init_module完成。

linux3.5.2/kernel/module.c:3009

/* This is where the real work happens */SYSCALL_DEFINE3(init_module, void __user *, umod,       unsigned long, len, const char __user *, uargs){    struct module *mod;    int ret = 0;    ……    /* Do all the hard work */    mod = load_module(umod, len, uargs);//模块加载    ……    /* Start the module */    if (mod->init != NULL)       ret = do_one_initcall(mod->init);//模块init函数调用    ……    return 0;}

系统调用init_module由SYSCALL_DEFINE3(init_module…)实现,其中有两个关键的函数调用。load_module用于模块加载,do_one_initcall用于回调模块的init函数。

函数load_module的实现为。

linux3.5.2/kernel/module.c:2864

/* Allocate and load the module: note that size of section 0 is always   zero, and we rely on this for optional sections. */static struct module *load_module(void __user *umod,                unsigned long len,                const char __user *uargs){    struct load_info info = { NULL, };    struct module *mod;    long err;    ……    /* Copy in the blobs from userspace, check they are vaguely sane. */    err = copy_and_check(&info, umod, len, uargs);//拷贝到内核    if (err)       return ERR_PTR(err);    /* Figure out module layout, and allocate all the memory. */    mod = layout_and_allocate(&info);//地址空间分配    if (IS_ERR(mod)) {       err = PTR_ERR(mod);       goto free_copy;    }    ……    /* Fix up syms, so that st_value is a pointer to location. */    err = simplify_symbols(mod, &info);//符号解析    if (err < 0)       goto free_modinfo;    err = apply_relocations(mod, &info);//重定位    if (err < 0)       goto free_modinfo;    ……}

函数load_module内有四个关键的函数调用。copy_and_check将模块从用户空间拷贝到内核空间,layout_and_allocate为模块进行地址空间分配,simplify_symbols为模块进行符号解析,apply_relocations为模块进行重定位。

由此可见,模块加载时,内核为模块文件main.ko进行了链接的过程!

至于函数do_one_initcall的实现就比较简单了。

linux3.5.2/kernel/init.c:673

int __init_or_module do_one_initcall(initcall_t fn){    int count = preempt_count();    int ret;    if (initcall_debug)       ret = do_one_initcall_debug(fn);    else       ret = fn();//调用init module    ……    return ret;}

即调用了模块的入口函数init。

模块卸载

模块卸载由内核的系统调用delete_module完成。

linux3.5.2/kernel/module.c:768

SYSCALL_DEFINE2(delete_module, const char __user *, name_user,        unsigned int, flags){    struct module *mod;    char name[MODULE_NAME_LEN];    int ret, forced = 0;    ……    /* Final destruction now no one is using it. */    if (mod->exit != NULL)       mod->exit();//调用exit module    ……    free_module(mod);//卸载模块    ……}

通过回调exit完成模块的出口函数功能,最后调用free_module将模块卸载。

结论

如此看来,内核模块其实并不神秘。传统的用户程序需要编译为可执行程序才能执行,而模块程序只需要编译为目标文件的形式便可以加载到内核,有内核实现模块的链接,将之转化为可执行代码。同时,在内核加载和卸载的过程中,会通过函数回调用户定义的模块入口函数和模块出口函数,实现相应的功能。

相关推荐:《Linux视频教程》

以上就是linux中引入模块机制有什么好处的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/321426.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月5日 09:59:09
下一篇 2025年11月5日 10:00:27

相关推荐

  • python pexpect模块是什么?

    pexpect模块用于自动化交互式命令行程序,其核心是expect机制,通过等待特定输出并发送响应实现控制,常用于自动登录、文件传输等场景,支持spawn启动进程、expect等待提示、sendline输入内容及interact交还控制权,主要适用于Unix/Linux系统,Windows需借助扩展…

    2025年12月15日
    000
  • Python 环境搭建从入门到进阶的完整流程

    首先安装Python官方解释器并添加至PATH,验证版本后使用venv创建虚拟环境隔离依赖,通过pip管理包并导出requirements.txt,推荐用VS Code或PyCharm开发,配合black、flake8等工具提升代码质量,科学计算项目可选Conda管理多环境与重型库。 选择并安装 P…

    2025年12月15日
    000
  • 如何在python django框架里搭建环境?

    首先配置Python环境并创建虚拟环境,然后安装Django并初始化项目。具体步骤为:安装Python 3.8+,使用venv创建隔离环境,激活后通过pip install django安装框架,再用django-admin startproject创建项目,运行runserver启动服务,最后生成…

    2025年12月15日
    000
  • 如何使用python中的pypy解释器?

    PyPy是Python的高性能替代解释器,通过JIT技术提升执行速度。安装方式因系统而异:Ubuntu用sudo apt install pypy3,macOS用brew install pypy3,Windows需从官网下载并配置环境变量。运行脚本使用pypy3命令,如pypy3 hello.py…

    2025年12月15日
    000
  • 解决macOS上pyhdf安装失败:‘hdf.h’文件未找到错误

    在macOS系统上安装`pyhdf`库时,若遇到“`hdf.h` file not found”错误,通常是由于缺少底层的HDF库及其头文件。本文将详细指导您如何通过Homebrew安装所需的HDF依赖,并成功解决`pyhdf`的安装问题,确保您能顺利在macOS环境下使用该库。 引言 pyhdf是…

    2025年12月15日
    000
  • VSCode中Conda虚拟环境激活与使用疑难排解

    当在VSCode中遇到Conda虚拟环境无法正确激活,导致代码无法在指定环境中运行时,问题通常在于终端环境配置未能识别或加载正确的虚拟环境。本教程提供了一种直接通过导航至虚拟环境脚本目录并执行激活脚本的方法,以确保您的Python代码能够在预期的隔离环境中运行,解决终端提示符不显示环境名称的问题。 …

    2025年12月15日
    000
  • Streamlit中Markdown文本转换为可下载PDF报告的教程

    介绍如何在streamlit应用中将动态生成的markdown文本转换为可下载的pdf报告。文章详细阐述了通过将markdown首先转换为html,再利用`pdfkit`工具将其渲染为pdf的完整流程,并提供了集成到streamlit下载按钮的示例代码,解决了直接下载markdown导致文件损坏的问…

    2025年12月15日
    000
  • macOS环境下解决Python urllib3与LibreSSL的兼容性问题

    针对macos用户在使用python及urllib3时,因系统默认的libressl版本与urllib3 v2+要求的openssl 1.1.1+不兼容而导致的`notopensslwarning`,本文提供了一套综合解决方案。核心策略包括切换至homebrew安装的python环境、必要时降级ur…

    2025年12月15日
    000
  • Streamlit中将Markdown文本转换为可下载PDF报告的教程

    本教程详细指导如何在Streamlit应用中,将动态生成的Markdown文本内容转换为可下载的PDF报告。文章将介绍如何利用markdown2库将Markdown转换为HTML,再通过pdfkit库(依赖wkhtmltopdf)将HTML渲染为PDF文件,并最终使用Streamlit的st.dow…

    2025年12月15日
    000
  • 解决PyCharm项目面板文件夹消失问题:macOS权限配置指南

    当pycharm在macos环境下出现项目文件夹在项目面板中操作后消失的问题时,通常并非pycharm本身的配置错误,而是macos系统层面的文件权限限制所致。本文将详细指导用户如何通过调整macos的隐私与安全性设置,赋予pycharm访问项目文件所需的权限,从而彻底解决这一困扰,确保开发流程的顺…

    2025年12月15日
    000
  • 如何使用Xvfb在GitLab CI/CD中运行Pyglet渲染测试

    本文详细介绍了在GitLab CI/CD无头环境中运行Pyglet渲染测试时遇到的`NoSuchConfigException`问题,并提供了一套完整的解决方案。通过正确配置和启动Xvfb虚拟显示服务器,确保Pyglet在持续集成流程中能够成功创建OpenGL上下文并执行图形渲染测试,从而实现自动化…

    2025年12月15日
    000
  • 处理压缩的.tar.Z文件:Python与Pandas的实战指南

    本文旨在解决在python环境中处理`.tar.z`格式压缩文件时遇到的常见问题,特别是当文件被错误地重命名导致无法读取数据时。我们将深入探讨`.tar`和`.z`扩展名的含义,并提供使用python标准库`tarfile`模块进行正确解压缩和数据读取的专业教程,确保您能高效地处理这类双重压缩的归档…

    好文分享 2025年12月15日
    000
  • 解决VS Code中Python解释器差异导致的运行问题

    本文旨在解决vs code中python代码运行结果与终端不一致的问题,尤其是在使用python 3特有语法(如`print()`函数的`sep`参数)时出现的错误。核心原因通常是vs code内部选择了错误的python解释器版本。教程将详细指导用户如何验证、选择并配置正确的python 3解释器…

    2025年12月15日
    000
  • Python FileNotFoundError 深度解析与文件路径处理教程

    本文深入探讨了python中常见的`filenotfounderror`(错误码2),详细解析了其发生原因,主要归结为文件路径不正确或对当前工作目录的误解。教程提供了识别、诊断和解决此类错误的实用方法,包括理解相对路径与绝对路径、使用`os`模块进行路径管理和调试,并通过具体代码示例指导读者正确处理…

    2025年12月15日
    000
  • 解决Kivy安装失败:Python版本兼容性问题指南

    kivy安装失败通常是由于python版本不兼容。本文详细解析了当kivy尚不支持最新python版本(如3.12)时,如何通过选择合适的python环境或使用虚拟环境来成功安装kivy,确保开发环境的稳定性和兼容性。 理解Kivy安装失败的常见原因 在尝试使用pip install kivy命令安…

    2025年12月15日
    000
  • 使用Python监控动态网页库存并发送Discord通知:从静态抓取到无头浏览器

    本文旨在指导读者如何使用Python构建一个商品库存监控机器人,并实时通过Discord发送通知。文章将深入探讨在面对JavaScript动态加载内容的网站时,传统网页抓取工具(如BeautifulSoup)的局限性,并详细介绍如何利用无头浏览器(如Selenium)来模拟用户行为、获取动态数据,最…

    2025年12月15日
    000
  • 解决 NumPy 安装中 Meson 构建系统错误的指南

    本文旨在解决在 windows 环境下使用 `pip` 安装 numpy 时遇到的 meson 构建系统错误,特别是涉及 `attributeerror: ‘nonetype’ object has no attribute ‘endswith’` 和…

    2025年12月15日
    000
  • 解决AWS Lambda Docker容器中Pytest重复执行问题

    在使用aws sam本地调用docker容器时,pytest测试框架可能出现重复执行的情况。这通常是由于dockerfile中对entrypoint指令的误用造成的。aws lambda基础镜像已预设其运行时入口点,自定义entrypoint会与基础镜像冲突。通过移除dockerfile中自定义的e…

    2025年12月15日
    000
  • 深入理解 Hatch 虚拟环境存储机制与自定义实践

    hatch 作为一个现代 python 项目管理工具,默认将虚拟环境存储在其管理的数据目录中,而非项目根目录。本文将解释 hatch 采用这种策略的原因,并提供详细教程,指导用户如何利用 `–data-dir` 选项自定义虚拟环境的存储位置,从而满足特定项目或工作流的需求,同时探讨这种默…

    2025年12月15日
    000
  • 通过SSH终端访问远程GUI应用程序的专业指南

    本教程详细介绍了如何在windows系统上,利用x11转发技术通过ssh连接远程linux设备(如raspberry pi),并显示其gui应用程序(如tkinter界面)。通过配置putty的x11转发功能并运行xming x服务器,开发者可以便捷地在本地调试和交互远程gui,无需频繁切换物理连接…

    2025年12月15日
    000

发表回复

登录后才能评论
关注微信