Linux 内核模块 - 访问内存映射
Linux kernel module - accessing memory mapping
我 运行 遇到了一些关于内核模块加载的奇怪问题,我怀疑它与链接和加载有关。如何在将每个部分加载到内存后(从模块本身内部)以编程方式找出每个部分的地址。比如 .bss / .data / .text 等等。
来自阅读本文
https://lwn.net/Articles/90913/
有点像我要找的直接。
您可以从用户空间(需要 root 权限)看到这些部分开始这样的地址:
sudo cat /sys/module/<modulename>/sections/.text
我浏览了 syfs 如何检索这些地址,我发现了以下内容:
struct module
中有一段属性
309 /* Section attributes */
310 struct module_sect_attrs *sect_attrs;
这个attrs是一堆attr结构
1296 struct module_sect_attrs {
1297 struct attribute_group grp;
1298 unsigned int nsections;
1299 struct module_sect_attr attrs[0];
1300 };
你要查找的教派属性在哪里
1290 struct module_sect_attr {
1291 struct module_attribute mattr;
1292 char *name;
1293 unsigned long address;
来自模块的代码 THIS_MODULE
宏实际上是一个指向 struct module
对象的指针。它的 module_init
和 module_core
字段指向内存区域,其中加载了所有模块部分。
据我了解,模块代码无法访问部分划分(struct load_info
在模块加载到内存后被删除)。但是有了模块的文件,您可以在加载后轻松推断出部分的地址:
module_init:
- init sections with code (.init.text)
- init sections with readonly data
- init sections with writable data
module_core:
- sections with code (.text)
- sections with readonly data
- sections with writable data
如果多个部分适合一个类别,它们的放置顺序与模块文件中的顺序相同。
在模块的代码中,您还可以打印其任何符号的地址,并在计算出该部分的开始后包含该符号。
虽然这个问题已经有五年了,但我想我会贡献我的两分钱。我能够以一种受 Alex Hoppus 回答启发的 hack-y 方式访问内核的部分。我不提倡这样做,除非你正在编写内核模块来调试东西或了解内核等。
无论如何,我将以下两个结构复制到我的模块中以帮助解决不完整的类型。
struct module_sect_attr {
struct module_attribute mattr;
char *name;
unsigned long address;
};
struct module_sect_attrs {
struct attribute_group grp;
unsigned int nsections;
struct module_sect_attr attrs[0];
};
然后,在我的模块初始化函数中,我执行以下操作以获取节地址。
unsigned long text = 0;
unsigned int nsections = 0;
unsigned int i;
struct module_sect_attr* sect_attr;
nsections = THIS_MODULE->sect_attrs->nsections;
sect_attr = THIS_MODULE->sect_attrs->attrs;
for (i = 0; i < nsections; i++) {
if (strcmp((sect_attr + i)->name, ".text") == 0)
text = (sect_attr + i)->address;
}
最后需要注意的是,如果你要查找.rodata
、.bss
、或.data
的地址,你需要定义常量全局变量,未初始化的全局变量, 或常规全局变量,如果您不想省略这些部分。
我 运行 遇到了一些关于内核模块加载的奇怪问题,我怀疑它与链接和加载有关。如何在将每个部分加载到内存后(从模块本身内部)以编程方式找出每个部分的地址。比如 .bss / .data / .text 等等。
来自阅读本文 https://lwn.net/Articles/90913/
有点像我要找的直接。
您可以从用户空间(需要 root 权限)看到这些部分开始这样的地址:
sudo cat /sys/module/<modulename>/sections/.text
我浏览了 syfs 如何检索这些地址,我发现了以下内容: struct module
中有一段属性309 /* Section attributes */
310 struct module_sect_attrs *sect_attrs;
这个attrs是一堆attr结构
1296 struct module_sect_attrs {
1297 struct attribute_group grp;
1298 unsigned int nsections;
1299 struct module_sect_attr attrs[0];
1300 };
你要查找的教派属性在哪里
1290 struct module_sect_attr {
1291 struct module_attribute mattr;
1292 char *name;
1293 unsigned long address;
来自模块的代码 THIS_MODULE
宏实际上是一个指向 struct module
对象的指针。它的 module_init
和 module_core
字段指向内存区域,其中加载了所有模块部分。
据我了解,模块代码无法访问部分划分(struct load_info
在模块加载到内存后被删除)。但是有了模块的文件,您可以在加载后轻松推断出部分的地址:
module_init:
- init sections with code (.init.text)
- init sections with readonly data
- init sections with writable data
module_core:
- sections with code (.text)
- sections with readonly data
- sections with writable data
如果多个部分适合一个类别,它们的放置顺序与模块文件中的顺序相同。
在模块的代码中,您还可以打印其任何符号的地址,并在计算出该部分的开始后包含该符号。
虽然这个问题已经有五年了,但我想我会贡献我的两分钱。我能够以一种受 Alex Hoppus 回答启发的 hack-y 方式访问内核的部分。我不提倡这样做,除非你正在编写内核模块来调试东西或了解内核等。
无论如何,我将以下两个结构复制到我的模块中以帮助解决不完整的类型。
struct module_sect_attr {
struct module_attribute mattr;
char *name;
unsigned long address;
};
struct module_sect_attrs {
struct attribute_group grp;
unsigned int nsections;
struct module_sect_attr attrs[0];
};
然后,在我的模块初始化函数中,我执行以下操作以获取节地址。
unsigned long text = 0;
unsigned int nsections = 0;
unsigned int i;
struct module_sect_attr* sect_attr;
nsections = THIS_MODULE->sect_attrs->nsections;
sect_attr = THIS_MODULE->sect_attrs->attrs;
for (i = 0; i < nsections; i++) {
if (strcmp((sect_attr + i)->name, ".text") == 0)
text = (sect_attr + i)->address;
}
最后需要注意的是,如果你要查找.rodata
、.bss
、或.data
的地址,你需要定义常量全局变量,未初始化的全局变量, 或常规全局变量,如果您不想省略这些部分。