Linux内核API __module_text_address

__module_text_address函数功能描述:该函数的功能是获得一个模块指针,它要满足条件: addr所表示的内存地址落在该模块的代码段中。

__module_text_address文件包含

#include <linux/module.h>

__module_text_address函数

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

函数定义格式:

struct module *__module_text_address( unsigned long addr )

__module_text_address输入参数说明

addr:表示内存地址。

__module_text_address返回参数说明

返回值是一个struct module类型的指针,如果内存地址addr在某一模块的代码段内,则返回指向该模块的指针,如果addr不在模块的地址空间内或者它不在代码段内,则返回NULL。

__module_text_address实例解析

编写测试文件:__module_text_address.c

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

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

int fun_a(void)
{
    return 0;
}
static int var_b = 4;

模块初始化函数:

int __init __module_text_address_init(void)
{
    unsigned long addr = (unsigned long)fun_a;      //addr为函数fun_a的入口地址
    struct module * ret ;
    preempt_disable( );                             //禁止抢占
    ret = __module_text_address(addr) ;
    preempt_enable( );                              //允许抢占

    /* 如果查找成功,则输出该模块的信息 */
    printk("it's about fun_a:\n");
    if( ret ! = NULL )
    {
        printk("ret->name: %s\n", ret->name);       //输出模块名
        printk("ret->state: %d\n", ret->state);     //输出模块状态
        /* 输出模块core段所占空间大小 */
        printk("ret->core_size: %d\n", ret->core_size);
    }
    else
    {
        printk("fun_a is not in text area! \n");
    }
    addr = (unsigned long)&var_b;                 //addr为静态全局变量var_b的地址
    preempt_disable( );
    ret = __module_text_address(addr) ;
    preempt_enable( );

    /* 如果查找成功,则输出该模块的信息 */
    printk("\nit's about var_b:\n");
    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段所占空间大小
    }
    else
    {
        printk("var_b is not in text area! \n");
    }
    return 0;
}

模块退出函数:

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

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

module_init(__module_text_address_init);
module_exit(__module_text_address_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod __module_text_address.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
Linux内核API __module_text_address

结果分析:

在该测试程序中,定义了一个函数fun_a( ),它存在于程序空间的代码段中,定义了一个全局静态变量var_b,它将位于程序空间中的数据段。

程序示例中调用__module_text_address( )时,为了防止模块被释放,需要禁止抢占,宏preempt_disable( )和preempt_enable( )分别用来实现禁止内核抢占和允许内核抢占。

首先将fun_a( )的入口地址作为实参传递给__module_text_address( )函数,该函数是判断所给的实参地址是否位于某一模块代码段中的,并且返回相应的模块指针。从输出信息可知,ret不为空,并且ret->name为“__module_text_address”, ret->state为1, ret->core_size为12501字节。以上说明fun_a( )的入口地址确实位于某一模块的代码段,而且该模块为当前正被加载的模块__module_text_address。

然后将全局静态变量var_b的地址作为实参传递给__module_text_address( )函数,从输出信息可知,由输出语句为“var_b is not in text area! ”可知ret为空。这说明var_b所在的内存单元并不在模块的代码段,因为var_b是全局静态变量,它是存在于数据段中的。

函数fun_a( )和变量var_b在模块插入到内核后,是作为内核符号存在的,在虚拟文件系统proc的kallsyms文件中有对它们相关的描述。

在下图显示的两行中,关于fun_a的显示,第二列为“t”,它表示符号fun_a位于代码段。关于var_b的显示,第二列为“d”,它表示var_b位于数据段。这与上面的测试结果是一致的。
Linux内核API __module_text_address

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程