精华内容
下载资源
问答
  • linux模块开发初探

    2020-07-28 17:00:27
    新手入门,绕不开HelloWord,本章写一个最简单的helloword模块,从编译到加载,再到验证,没有问题。 第一步 创建hello.c文件,代码如下: #include <linux/module.h> /* Needed by all modules */ #...

    新手入门,绕不开HelloWord,本章写一个最简单的helloword模块,从编译到加载,再到验证,没有问题。

    第一步

    创建hello.c文件,代码如下:

    #include <linux/module.h>   /* Needed by all modules */
    #include <linux/kernel.h>   /* Needed for KERN_INFO */
    #include <linux/init.h>
    
    int __init hello_module_init(void)
    {
        printk(KERN_INFO "Hello world.\n");
        return 0;//A non 0 return means init_module failed; module can't be loaded.
    }
    
    void __exit hello_module_exit(void)
    {
        printk(KERN_INFO "Bye world.\n");
    }
    
    module_init(hello_module_init);
    module_exit(hello_module_exit);
    

    内核模块提供module_init和module_exit两个接口,其实是宏定义, 这些宏在linux / init.h中定义。 需要注意的是,必须在调用宏之前定义init和exit函数,否则会出现编译错误。

    printk函数其实是内核态的printf,是内核日志接口,有8个优先级,对应有宏,可以在linux / kernel.h中查看。 如果未指定优先级,默认使用DEFAULT_MESSAGE_LOGLEVEL优先级别。

    第二步

    编写makefile,内容如下:

    obj-m += hello.o
    hello-y := 
    all:
    	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    
    clean:
    	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
    

    obj-m表示编译生成可加载模块。相对应的,obj-y表示直接将模块编译进内核。

    这里并没有输入hello.c源文件,这得益于makefile的自动推导功能。

    make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules

    -C选项:此选项指定内核源码的位置,make在编译时会进入内核源码目录执行编译,编译完成时返回。

    M=$(PWD):需要编译的模块源文件地址。

    第三步

    在终端执行make,无报错,在源码目录下会生成hello.ko文件,如下:

    [root@localhost helloword]# ls
    hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  Makefile  modules.order  Module.symvers

    此时执行命令以验证:

    [root@localhost helloword]# insmod hello.ko 
    [root@localhost helloword]# dmesg |tail -n 1
    [25991.570137] Hello word.
    [root@localhost helloword]# rmmod hello.ko 
    [root@localhost helloword]# dmesg |tail -n 2
    [25991.570137] Hello word.
    [26029.873588] Bye world.
    [root@localhost helloword]# 

    可以看到,我的模块是正常加载,并能正常退出。

    总结

    这只是最简单的模块开发步骤,当然要构建一个复杂的模块代码,makefile也是很关键。自linux2.4开始,linux使用两个宏module_init和module_exit来完成模块的初始化和销毁。

    内核开发,需要对应linux源码看,这样才能很清楚的找到接口的实现。内核说起来很难,其实,并没有想像的那么可怕,有问题在开源社区都能找到答案。

    接下来,我会自己先玩一些复杂的模块,玩通了再来写博客,有意思又能成长的事情,欢迎一起交流。

    展开全文
  • 当新加载的模块未声明许可证或者许可证不被内核认可的时候,内核将输出kernel tainted警告。这种情况,一般被称为内核污染。 声明许可证的方法: MODULE_LICENSE(“licensename”) 声明许可证的举例 MODULE_...

    1内核污染问题

    当新加载的模块未声明许可证或者许可证不被内核认可的时候,内核将输出kernel tainted警告。这种情况,一般被称为内核污染。

    声明许可证的方法:

    MODULE_LICENSE(“licensename”)

    声明许可证的举例

    MODULE_LICENSE("DualBSD/GPL");

    MODULE_LICENSE("GPL");

    MODULE_LICENSE("BSD ");

    内核认可(即不会认为受到污染)的证书类型如下:

    GPL

    BSD

    DualBSD/GPL

    内核污染标志本身上不会对内核的使用产生任何影响。

    2符号导出问题

    导出方法有以下两种

    EXPORT_SYMBOL

    EXPORT_SYMBOL_GPL

    导出的“符号”可以是变量,也可以是函数。

    导出和”static”概念有区别:

    1:static在内核中的含义也只是限定一个变量只有本文件可以使用。

    2:Static限制的变量也可以导出。

    3:所有导出了的变量名都是唯一的。

    4:只要导出了的变量就可以在其他模块使用,无论次变量是否static修饰。

    5:一个变量或函数能不能由本模块中的其他文件使用,是由static修饰决定,规则与普通C语言规则一样,无论此函数是否导出。

    总结地说,static的限制范围作用于模块本身以及模块自己的编译过程。导出的作用范围是模块加载入内核后的内核符号表。

    3模块版本问题

    CONFIG_MODVERSIONS内核选项打开后,加载模块时,内核将会强制验证模块的版本,如果和内核版本不一致,内核会拒绝加载。

    模块的内核版本记录在于模块一起编译的.mod.c文件中,一般形式如下:

    MODULE_INFO(vermagic,VERMAGIC_STRING);

    v2.6.34.8的menuconfig中只有version检查的选项,

    但是(不知道是内核升级还是发布版定制导致),后续还出现了校验内核接口CRC的版本校验,导致即使同一个小版本号的内核,只要源码树不同,编译出的模块就可能无法互通。

    解决办法:

    1:模块与内核在同一个目录树下编译

    2:解除内核的版本检查机制。

    4符号寻址问题

    内核所有函数的名字与地址的对应关系都是被内核保存了的。从/proc/kallsyms可以看到这个对应关系。新加入的模块,想调用内核中已经导出的函数,就需要查这张表。同样,内核中已有的模块,想调用新加入的模块的函数,也需要查找这张表。幸运的是,这个复杂的查找过程对于我们来说是完全透明的。

    从/proc/kallsyms文件中也可以看见你刚加载的模块的函数,以及他们在内核空间中的地址。

    5编译时自动补齐的部分

    编译模块时产生的.mod.c文件记录了这个模块的很多信息,比如版本。这个.c文件将与你自己写的.c模块一起编译成模块。

    6自动drop的代码段

    当一个函数被标注为__init的时候,它将被加载并使用一次,然后保存其代码的内存将被释放。这是一个半自动的过程:编程者指定哪些代码只用一次,而内核按照编程者的指定丢弃使用过的代码。

    一般模块加载时的入口函数会被标记为__init。这个函数与模块中其他函数的不同就在于:其他函数将被加载进内核的代码空间中,直到卸载模块为止;而这个“初始化函数”,开始时也会被加载进内核的代码空间中,但是内核在调用过一次后,就会将这段代码自动自动丢弃掉,内核的代码空间中再也看不见这个函数了。

    转自:http://bbs.chinaunix.net

     

    展开全文
  • 1.准备编译 ko 的 linux 环境:  本人使用 ubuntu 9.10. 2.查看系统的版本:  使用 uname -r 命令, 本人系统是 2.6.31-22-generic. 3.安装内核头文件:  sudo apt-get install linux-headers-`uname -r`  ...

    1.准备编译 ko 的 linux 环境:

       本人使用 ubuntu 9.10.

    2.查看系统的版本:

       使用 uname -r 命令, 本人系统是 2.6.31-22-generic.

    3.安装内核头文件:

       sudo apt-get install linux-headers-`uname -r`

       本人使用: sudo apt-get install linux-headers-2.6.31-22-generic. 可能会得到下面的信息:

       linux-headers-2.6.31-22-generic is already the newest version.
       0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    4.当然, gcc /make 等工具天生就是需要的,这些一般不用安装,系统自带了。

    5.编写 c code:

       本人的 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 enter/n");
           return 0;
       }

       static void hello_exit(void)
       {
           printk(KERN_ALERT "hello world exit/n");
       }

       module_init(hello_init);
       module_exit(hello_exit);

       MODULE_AUTHOR("Alex Xia");
       MODULE_DESCRIPTION("A single hello world module");
       MODULE_ALIAS("a simplest module");

     

    6.编写Makefile,注意,命令前面是 Tab 键,不是空格。

       本人的 Makefile :

       obj-m:=hello.o
       KERNELBUILD:=/lib/modules/2.6.31-22-generic/build
       default:
                  make -C $(KERNELBUILD) M=$(shell pwd) modules
       clean:
                  rm -rf *.o *.ko *.mod.c *.cmd .tmp_versions

     

    7.在Makefile 一级的目录中执行 make, 生成 hello.ko 等文件。

    8.使用 sudo insmod hello.ko 将模块插入内核系统。

    9.如果没看到 module_init()注册的函数执行中的打印信息,使用 dmesg 命令查看系统日志。本人有看到 “hello world enter”。

    10.使用 sudo rmmod hello 从内核中移出 hello.ko 模块。使用 dmesg 命令查看系统日志。本人有看到 “hello world exit”。

     

    展开全文
  • Linux内核模块开发

    2020-10-17 20:46:05
    Linux内核模块开发 1. 源代码文件结构   下面是一个最基本的内核模块源代码结构,任何模块项目都需要包含这些内容 #include <linux/module.h> /*模块初始化函数*/ static int module_init_func(void) { ...

    Linux内核模块开发

    1. 源代码文件结构

      下面是一个最基本的内核模块源代码结构,任何模块项目都需要包含这些内容

    #include <linux/module.h>
    
    /*模块初始化函数*/
    static int module_init_func(void) 
    {
        return 0;
    }
    
    /*模块卸载函数*/
    static void module_exit_func(void)
    {
    
    }
    
    module_init(module_init_func);
    module_exit(module_exit_func);
    MODULE_LICENSE("GPL");
    

    2. 常用的头文件

      开发内核模块通常会用到以下头文件

    #include <linux/module.h> // 内核模块相关操作,如模块注册,卸载等等
    #include <linux/kernel.h> // 内核输入输出等功能函数
    #include <linux/fs.h> // 虚拟文件系统相关操作,如打开文件,关闭文件等等
    #include <linux/mm.h> // 内存映射相关操作
    #include <linux/slab.h> // 内核动态分配,kmalloc/kfree等
    #include <linux/vmalloc.h> // 内核动态分配, vmalloc/vfree等
    #include <linux/mman.h> // 内存映射相关操作
    #include <linux/kallsyms.h> // 查找内核符号表的相关函数 kallsyms_lookup_name
    #include <linux/uaccess.h> // 操作用户空间内存的相关函数
    #include <linux/err.h>	// 处理Linux错误码的相关函数
    #include <linux/types.h> // Linux常用的基本数据类型定义,如uint8_t,size_t等等
    

    3. 编译单个源代码文件的内核模块

      最基本的用于编译一个内核模块的Makefile如下

    # 这里设置模块名称,模块名称为源代码文件名去掉后缀名
    MODULE_NAME := module_name
    
    # 内核构建系统会根据传递给其的M变量来找到这个Makefile文件并将其include,通过检查KERNELRELEASE变量,可以将传递给内核构建系统的内容和本Makefile单独的操作分开以避免相互影响
    ifneq ($(KERNELRELEASE),)
    
    # 此内容传递给内核构建系统,因此只向内核构建系统传递其必须的变量(即obj-m),避免污染内核构建系统中的其他变量
    obj-m := $(MODULE_NAME).o
    
    else
    # 下面的内容不需要被内核构建系统使用
    # 通过ccflags-y变量可以增加编译时的编译参数
    ccflags-y := 
    
    # 注意这里传递给内核构建系统的M变量,内核构建系统将在M变量保存的目录中搜索Makefile文件,并将其include
    all:
    	$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) ccflags-y=$(ccflags-y) modules
    
    clean:
    	$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
    endif
    

    4. 编译多个源代码文件的内核模块

      如果要编译的内核模块包括了多个源代码,需要对Makefile进行一些调整

    # 这里设置模块名称(不需要为源代码名称)
    MODULE_NAME := module_name
    
    ifneq ($(KERNELRELEASE),)
    
    obj-m := $(MODULE_NAME).o
    # 这里写源代码列表,需要将后缀名.c改为.o,以空格分隔
    $(MODULE_NAME)-objs := sourcecode1.o sourcecode2.o
    
    else
    
    # 添加额外的编译选项
    ccflags-y := 
    all:
    	$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) ccflags-y=$(ccflags-y) modules
    
    clean:
    	$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
    
    endif
    
    展开全文
  • linux内核模块开发

    2017-04-02 21:55:58
    linux内核模块开发 什么是内核模块?  linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用需要的组件呢?  方法一:把所有的组件编译进内核文件,但这样会导致生成的内核文件过大和调整组件不方便。...
  • LInux 内核模块开发实例编写一个helloworld内核模块编写编译内核模块Makefile 编写一个helloworld内核模块 #include &amp;lt;linux/init.h&amp;gt; #include &amp;lt;linux/module.h&amp;gt; ...
  • 实用标准文案 linux 驱动开发笔记 7 驱动模块开发流程 一驱动模块的搭建 1 在 Drivers 目录下建立自己的模块目录 2 建立 Makefile 文件见上一篇博客 3 建立源文件源文件矿建如下其中这两个函数式必须实现的 #include...
  • Linux允许用户通过插入模块,实现干预内核的目的。一直以来,对linux模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析。 模块的Hello World! 我们通过创建一个简单的模块进行测试。首先是源文件...
  • Linux模块机制浅析 Linux允许用户通过插入模块,实现干预内核的目的。一直以来,对linux的模块机制都不够清晰,因此本文对内核模块的加载机制进行简单地分析。 模块的Hello World! 我们通过创建一个简单的模块进行...
  •   这篇文章旨在介绍Linux内核动态模块开发时的基本结构,以及如何编译开发的模块。 Linux内核模块开发   我们知道Linux的内核是可以定制的,在编译之前我们可以通过make menuconfig对我们的内核进行配置。...
  • 内核模块开发相关链接: https://www.thegeekstuff.com/2013/07/write-linux-kernel-module/入门教程;insmod, rmmod, modinfo等相关命令; https://www.thegeekstuff.com/2010/08/make-utility/make 工具使用教程;...
  • Linux的模块开发注意一、模块Linux模块是linux的特色,他可以在需要的时候动态加载进内核,也可以在合适的时候移除内核,这样就保证内核的简洁高效二、代码分析#include <linux/init.h> #include <linux/module.h> ...
  • linux内核模块开发基础

    千次阅读 2016-05-06 20:35:50
    1. 什么是内核模块 ... 原因:Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢,方法1:把所有的组件都编译键内核,即:zImage或bzImage,但这样会导致一个问题:占用内存过多。然后
  • 移远4G通信模块linux环境下开发文档,以及linux驱动程序,根据开发文档流程进行,可实现在linux环境下4G通信。
  • Linux下Apache模块开发

    2018-12-07 16:48:50
    环境:Linux RedHat 首先来介绍下apache的一个工具apxs。apxs是一个为Apache HTTP服务器编译和安装扩展模块的工具,用于... 安装好Apache服务器后,安装目录的bin目录下包含apxs工具。 模块开发代码 mod_jump_...
  • Linux 驱动开发前奏(模块编程) 转自Linux公社 一、linux内核模块简介  linux内核整体结构非常庞大,其包含的组件也非常多。我们怎么把需要的部分都包含在内核中呢?  一种办法是把所有的需要的...
  • 注:以下程序只是在我机器上测试通过,但代码不一定合理或高效,只是想了解一下内核模块开发流程,以及工作流程 例子来源于网络,在此表示感谢 [cpp] view plain copy [root@localhost module]# cat...
  • 在写一个netfilter相关的内核模块,发现一些开发内核模块时要注意的问题,简记于此,如有谬误,还请不吝指正! 1、内核模块内不能使用stdlib,stdio等C标准库,内核在lib/string.c下实现了一些常用函数strcpy....
  • Linux 内核模块开发基本知识

    千次阅读 2014-05-30 23:28:49
    Linux 内核模块开发 1、 什么是内核模块? 避免内核镜像太大,占用太多的内存资源,所以可以编译进内核模块中去。 特点:动态的加载与卸载;不会被编译进内核镜像文件。 2、 学习方法。 范例程序->思维导图...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,347
精华内容 2,938
关键字:

linux模块开发

linux 订阅