Linux内核模块 - 访问内存映射

时间:2015-07-15 23:03:33

标签: linux-kernel android-kernel

我遇到了一些关于内核模块负载的奇怪问题,我怀疑它与链接和加载有关。如何以编程方式计算每个部分在内存中加载后的地址(从模块本身内部)。比如.bss / .data / .text等等。

阅读本文 https://lwn.net/Articles/90913/

我正在寻找的直接排序。

3 个答案:

答案 0 :(得分:2)

您可以看到这些部分从用户空间开始这样的地址(需要root权限):

sudo cat /sys/module/<modulename>/sections/.text

我浏览过syfs如何检索这些地址,我发现了以下内容: struct module

中有一个section属性
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 };

其中sect attr就是你要找的东西

1290 struct module_sect_attr {
1291         struct module_attribute mattr;
1292         char *name;
1293         unsigned long address;

答案 1 :(得分:1)

从模块的代码THIS_MODULE宏实际上是指向struct module对象的指针。其module_initmodule_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

如果有几个部分适合一个类别,则它们按照与模块文件中相同的顺序放置。

在模块的代码中,您还可以打印任何符号的地址,并在计算该部分的开始后,包含此符号。

答案 2 :(得分:0)

虽然这个问题已有5岁,但我认为我会贡献我的2美分。我能够以Alex Hoppus的回答为灵感,以一种骇人听闻的方式访问内核的各个部分。我不主张这样做,除非您正在编写内核模块以进行调试或了解内核等。

无论如何,我将以下两个结构复制到模块中,以帮助解决不完整的类型。

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的地址,则需要定义常量全局变量,未初始化的全局变量或如果您不想忽略这些部分,则分别使用常规全局变量。