__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,会出现如图所示的结果。
结果分析:
在该测试程序中,定义了一个函数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位于数据段。这与上面的测试结果是一致的。