当在内核模块中使用正常的attribute section
语法时,此节不会自动生成。
我试图在编译时将数据从源代码的不同地方放在一个特殊的部分,然后使用部分start
和end
符号在运行时检索该部分的所有数据。
在foo
段放置符号:
...
int var_on_foo __attribute__((section("foo"))) = 10;
...
然后试图访问foo
:
int* first_foo = __start_foo;
....
在用户空间中使用它完全没问题,因为编译器只是将所有节中的内容编译到elf中。但是在内核模块中使用它会导致错误:
[ 192.586590] simple_test: Unknown symbol __start_foo (err -2)
我怎么能告诉kbuild编译在我所有的特殊部分?
所以这里的一半答案可能对大多数人来说已经足够了:
这些节被编译进去,并且在大多数情况下该节不会被分割出来(因为分割内核模块被认为是一件坏事)。
但是在userland中使用section开始结束符号访问数据是不可能的,因为内核ko elf加载器(modules.c - load_module…)不会注意设置这些符号。
1。解决方案:(核心)
铁杆解决方案是修改load_module函数以访问mod_info结构体,在该结构体中解析节和符号的偏移量。
2。解决方案:
如果您使用节的目标是能够在一个地方从模块的各个地方收集数据,那么更简单的方法可能是:
#include <linux/elf.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
__attribute__((used)) static void barA(void)
{
static char my_value[] = "i want to be free";
static char *_magic_meta_string_my_value __attribute__((used)) = my_value;
}
__attribute__((used)) static void barB(void)
{
static char my_value[] = "i want to break free";
static char *_magic_meta_string_my_value_foo_bar_baz __attribute__((used)) = my_value;
}
static int __init init_magic_meta_section(void)
{
const struct mod_kallsyms *const kallsyms = THIS_MODULE->kallsyms;
for (unsigned int i = 0; i < kallsyms->num_symtab; i++) {
const Elf_Sym *const ksym = &kallsyms->symtab[i];
const char *const name = &kallsyms->strtab[ksym->st_name];
static const char ref_name[] = "_magic_meta_string";
static const unsigned int ref_name_length = sizeof((ref_name)) - 1;
if (strncmp(name, ref_name, ref_name_length) == 0) {
const char *const section_name = name + ref_name_length + 1;
const char *const first_dot = strchr(section_name, '.');
const long section_name_length = (long)first_dot - (long)section_name;
printk(KERN_INFO "symbol %u: %lx %lu %s for section %.*sn", i, (uintptr_t)ksym->st_value,
(uintptr_t)ksym->st_size, name, section_name_length, section_name);
const char **magic_ptr = (char **)ksym->st_value;
printk(KERN_INFO "and here the magic: (%s)n", *magic_ptr);
}
}
return 0;
}
在本例中,_magic_meta_string
是一个字符串,我们将其添加到我们想要重新找到的所有符号中。然后遍历所有模块符号,并搜索所有以该字符串开头的符号。
与userland中的sections_start和end符号不完全相同,但我想在大多数情况下已经足够了。
特别感谢@jo5ta帮我发现这个:)