Linux内核API完全参考手册(第2版)
上QQ阅读APP看书,第一时间看更新

2.1 函数:__module_address( )

文件包含:

        #include <linux/module.h>

函数定义:

在内核源码中的位置:linux-3.19.3/kernel/module.c

函数定义格式:struct module *__module_address(unsigned long addr)

函数功能描述:

函数__module_address( )根据给定的一个内存地址addr,获得该内存地址所在的模块。

输入参数说明:

addr:其值表示内存地址。

返回参数说明:

如果内存地址addr在某一模块的地址空间中,则返回指向该模块的结构体指针,否则返回NULL。其中关于结构体struct module的定义见本章中关于f ind_module( )函数的分析。

实例解析:

编写测试文件:__module_address.c

头文件及全局变量声明如下:

        #include <linux/module.h>
        #include <linux/init.h>
        MODULE_LICENSE("GPL");
        static int __init __module_address_init(void);
        static void __exit __module_address_exit(void);

模块初始化函数:

        int a_module(void) //此处定义一个自己添加的内核函数,函数参数必须写入void
        {
            return 0;
        }
        int __init __module_address_init(void)
        {
            struct module * ret ;                                   //用于接收测试函数返回值
            unsigned long addr = (unsigned long)a_module;            //得到内核符号a_module的地址
            /*调用__module_address( )函数之前,必须禁止中断,以防止模块在执行操作期间被释放*/
            preempt_disable( );    //禁止抢占
            ret = __module_address(addr) ;
            preempt_enable( );    //允许抢占
            /* 如果返回不为空,则输出该模块的信息 */
            if( ret ! = NULL )
            {
                printk("ret->name: %s\n", ret->name);               //输出模块名
                printk("ret->state: %d\n", ret->state);             //输出模块状态
                printk("ret->core_size: %d\n", ret->core_size);     //输出模块core段所占空间大小
                printk("refs of %s is %d \n", ret->name, module_refcount(ret));
                                                                    // 输出模块引用计数
            }
            else
            {
                printk("__module_address return NULL ! \n");
            }
            return 0;
        }

模块退出函数:

        void __exit __module_address_exit(void)
        {
            printk("module exit ok! \n");
        }

模块初始化及退出函数调用:

        module_init(__module_address_init);
        module_exit(__module_address_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod __module_address.ko插入模块,然后执行命令dmesg -c,出现如图2-1所示的结果。

图2-1 插入__module_address模块后系统输出信息

结果分析:

在该测试程序中,首先令函数__module_address ( )的参数addr取值为函数a_module( )的入口地址,显然addr所表示的内存地址在待加载模块__module_address中。

然后调用__module_address ( )函数,为了防止模块被释放,需要禁止抢占,宏preempt_disable( )和preempt_enable( )分别用来实现禁止内核抢占和允许内核抢占。如果查找到内存地址addr所属的模块,则输出该模块的name、state等信息。由图2-1中的输出信息可知,ret->name恰为“__module_address”, ret->state为1(即表示该模块处于正在被加载的MODULE_STATE_COMING状态,见下面关于枚举类型module_state的说明), ret->core_size为12469字节,然后调用module_refcount( )得到该模块的引用计数为1。

分析中涉及了枚举类型module_state,它定义了模块的三种状态,其具体定义请参见本章中关于函数f ind_module( )的分析。函数module_refcount( )的功能是得到模块的引用计数,具体请见本章中该函数的分析。