• 转载


        本文将直接了当的带你进入linux的模块编译。当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者能够看懂。之所以要写这篇文章,主要是因为 从书本上学的话,可能要花更长的时间才能学会整个过程,因为看书的话是一个学习过程,而我这篇文章更像是一个培训。所以实践性和总结性更强。通过本文你将 会学到编译一个模块和模块makefile的基本知识。以及加载(卸载)模块,查看系统消息的一些知识;

    声明:本文为初学者所写,如果你已经是一个linux模块编译高手,还请指正我文章中的错误和不足,谢谢

    第一步:准备源代码

    首先我们还是要来编写一个符合linux格式的模块文件,这样我们才能开始我们的模块编译。假设我们有一个源文件mymod.c。它的源码如下:

    mymodules.c

    1. #include <linux/module.h>     /* 引入与模块相关的宏 */
    2. #include <linux/init.h>        /* 引入module_init() module_exit()函数 */
    3. #include <linux/moduleparam.h> /* 引入module_param() */
    4
    5. MODULE_AUTHOR("Yu Qiang");
    6. MODULE_LICENSE("GPL");
    7
    8. static int nbr = 10;
    9. module_param(nbr, int, S_IRUGO);
    10.
    11. static int __init yuer_init(void)
    12.{
    13.    int i;
    14.    for(i=0; i<nbr; i++)
    15.    {
    16.        printk(KERN_ALERT "Hello, How are you. %d/n", i);
    17.    }
    18.    return 0;
    19.}
    20.
    21.static void __exit yuer_exit(void)
    22.{
    23.    printk(KERN_ALERT"I come from yuer's module, I have been unlad./n");
    24.}
    25.
    26. module_init(yuer_init);
    27. module_exit(yuer_exit);

    我 们的源文件就准备的差不多了,这就是一个linux下的模块的基本结构。第9行是导出我们的符号变量nbr。这样在你加载这个模块的时候可以动态修改这个 变量的值。稍后将演示。yuer_init()函数将在模块加载的时候运行,通过输出的结果可以看到我们的模块是否加载成功。


    第二步:编写Makefile文件
       
    首先还是来看看我们Makefile的源文件,然后我们再来解释;

    Makefile
    obj-m := modules.o                   #要生成的模块名    
    modules-objs:= mymod.o        #生成这个模块名所需要的目标文件

    KDIR := /lib/modules/`uname -r`/build   

    PWD := $(shell pwd)

    default:
    make -C $(KDIR) M=$(PWD) modules

    clean:
    rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions

    ARM平台

    Makefile

    obj-m += mymod.o
    KDIR := /home/workspace2/kernel/linux-2.6.25    #如果是用于arm平台,则内核路径为arm内核的路径

    PWD = $(shell pwd)
    all:
            make -C $(KDIR) M=$(PWD) modules
    clean:
            rm -rf *.o

    在arm板上插入是

    insmod mymod 

     
    如果出现以下错误
    insmod: chdir(/lib/modules): No such file or directory
     
    则运行
    mkdir /lib/modules/2.6.25 (与arm内核版本相同)
    并将mymod.ko文件复制到该目录下
    cp mymod.ko /lib/modules/2.6.25
     
    然后再执行 (insmod 只在/lib/modules/2.6.25目录下查找相关驱动模块)
    insmod mymod
     


    现在我来说明一下这个Makefile。请记住是大写的Makefile而不是小写的makefile;
    obj-m :这个变量是指定你要声称哪些模块模块的格式为 obj-m := <模块名>.o
    modules-objs :这个变量是说明声称模块modules需要的目标文件 格式要求   <模块名>-objs := <目标文件>
           切记:模块的名字不能取与目标文件相同的名字。如在这里模块名不能取成 mymod;
    KDIR   :这是我们正在运行的操作系统内核编译目录。也就是编译模块需要的环境
    M=     :指定我们源文件的位置
    PWD   :这是当前工作路径$(shell   )是make的一个内置函数。用来执行shell命令。


    第三步:编译模块

    现在我们已经准备好了我们所需要的源文件和相应的Makefile。我们现在就可以编译了。在终端进入源文件目录输入make
    运行结果:
        make[1]: Entering directory `/usr/src/linux-headers-2.6.24-24-generic'
        CC [M] /home/yuqiang/桌面/mymodule/mymodules.o
        LD [M] /home/yuqiang/桌面/mymodule/modules.o
        Building modules, stage 2.
        MODPOST 1 modules
        CC      /home/yuqiang/桌面/mymodule/modules.mod.o
        LD [M] /home/yuqiang/桌面/mymodule/modules.ko
        make[1]: Leaving directory `/usr/src/linux-headers-2.6.24-24-generic'


    第四步:加载/卸载我们的模块

    从上面的编译中我可以看到。已经有一个modules.ko生成了。这就是我们的模块了。现在我们就可以来加载了。
    首先在终端输入:sudo insmod modules.ko
    现在我们来看看我们的模块加载成功没有呢?
    在终端输入:dmesg | tail -12    这是查看内核输出信息的意思。tail -12 显示最后12条;
    显示结果如下:
        [17945.024417] sd 9:0:0:0: Attached scsi generic sg2 type 0
        [18046.790019] usb 5-8: USB disconnect, address 9
        [19934.224812] Hello, How are you. 0
        [19934.224817] Hello, How are you. 1
        [19934.224818] Hello, How are you. 2
        [19934.224820] Hello, How are you. 3
        [19934.224821] Hello, How are you. 4
        [19934.224822] Hello, How are you. 5
        [19934.224824] Hello, How are you. 6
        [19934.224825] Hello, How are you. 7
        [19934.224826] Hello, How are you. 8
        [19934.224828] Hello, How are you. 9

    看到了吧。我们的模块的初始化函数yuer_init();已经成功运行了。说明我们的模块已经加载成功;
    现在我们再来卸载模块试试看。
    在终端输入:sudo rmmod modules
    在终端输入:dmesg | tail -3
        [19934.224826] Hello, How are you. 8
    [19934.224828] Hello, How are you. 9
    [20412.046932] I come from yuer's module, I have been unlad.

    可以从打印的信息中看到,我们的模块的退出函数已经被执行了。说明我们的模块已经被成功的卸载了。到目前位置我们就已经算是对模块的编译到编译运行算是有了一个整体上的认识了。对于以后深入的学习还是应该有点帮助的。下面我们将在看看于模块相关的一些简单的操作。


    第五步:加载模块时传递参数
    在终端输入:sudo insmod module_name.ko nbr=4
    在终端输入:dmesg | tail -6
    显示结果如下:
    [20800.655694] Hello, How are you. 9
    [21318.675593] I come from onefile module, I have been unlad.
    [21334.425373] Hello, How are you. 0
    [21334.425378] Hello, How are you. 1
    [21334.425380] Hello, How are you. 2
    [21334.425381] Hello, How are you. 3

    这样我们就可以看到在模块加载的时候动态设置了我们的一个变量。初始化函数中的循环只执行了4次。
    可能你会问我怎么知道一个模块可以设置那些变量呢。当然,你可以先不设变量加载一次。然后可以在终端输入ls /sys/module/<modules_name>/parameters/来查看。在这里我们是这样输入的
    在终端输入:ls /sys/moedle/modules/parameters/
    显示结果:
    nbr

    如果我们的模块加载成功了。最后我们还可以通过modinfo来查看我们的模块信息。如下
    在终端输入:sudo modinfo modules.ko
        显示结果:
    filename:       modules.ko
    license:        GPL
    author:         Yu Qiang
    srcversion:     20E9C3C4E02D130E6E92533
    depends:       
    vermagic:       2.6.24-24-generic SMP mod_unload 586
    parm:           nbr:int

  • 相关阅读:
    结对项目:四则运算
    Word Count(C语言)
    自我介绍+软工5问
    如何在博客园中使用markdown
    如何设计一门语言(九)——类型
    如何设计一门语言(八)——异步编程和CPS变换
    如何设计一门语言(七)——闭包、lambda和interface
    时隔多年我又再一次体验了一把跟大神聊天的感觉
    20199107 2019-2020-2 《网络攻防实践》第4周作业
    20199107 2019-2020-2 《网络攻防实践》第3周作业
  • 原文地址:https://www.cnblogs.com/oracleloyal/p/5357958.html
Copyright © 2020-2023  润新知