在LKM中使用ELF部分

我在C中拥有这个POC,它在自定义节中保存了一些结构,然后遍历这些结构,显示它们的内容。

#include <stdio.h> char a, b, c; struct counter_info { int counter; char *name; } __attribute__((packed)); #define __PUT_STUFF_IN_SECTION(_name) \ do{ \ static struct counter_info __counter_info_##_name \ __attribute((__section__("counters"))) \ __attribute((__used__)) = { \ .name = #_name, \ .counter = 0, \ }; \ }while(0) extern struct counter_info __start_counters; extern struct counter_info __stop_counters; int main(int argc, char **argv){ printf("Start %p\n", &__start_counters); __PUT_STUFF_IN_SECTION(a); __PUT_STUFF_IN_SECTION(b); __PUT_STUFF_IN_SECTION(c); struct counter_info *iter = &__start_counters; for(; iter < &__stop_counters; ++iter){ printf("Name: %s | Counter: %d.\n", iter->name, iter->counter); } printf("End %p\n", &__stop_counters); return 0; } 

输出:

 Name: c | Counter: 0. Name: b | Counter: 0. Name: a | Counter: 0. 

输出如预期的那样,所以我试图在内核模块中做同样的事情:

HELLO-1.C

 #include <linux/module.h> #include <linux/kernel.h> char a, b, c; struct counter_info { int counter; char *name; } __attribute__((packed)); #define __PUT_STUFF_IN_SECTION(_name) \ do{ \ static struct counter_info __counter_info_##_name \ __attribute((__section__("counters"))) \ __attribute((__used__)) = { \ .name = #_name, \ .counter = 0, \ }; \ }while(0) extern struct counter_info __start_counters; extern struct counter_info __stop_counters; int init_module(void){ __PUT_STUFF_IN_SECTION(a); __PUT_STUFF_IN_SECTION(b); __PUT_STUFF_IN_SECTION(c); return 0; } void cleanup_module(void){ struct counter_info *iter = &__start_counters; for(; iter < &__stop_counters; ++iter){ printk(KERN_INFO "Name: %s | Counter: %d.\n", iter->name, iter->counter); } } 

Makefile文件:

 obj-m += hello-1.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

但是当我编译模块时,我得到了这些警告:

 WARNING: "__stop_counters" [/media/sf_procmon/procmon_kmodule/test/hello-1.ko] undefined! WARNING: "__start_counters" [/media/sf_procmon/procmon_kmodule/test/hello-1.ko] undefined! 

我的问题是:为什么不工作,我该如何使用LKM中的section属性?

编辑:

我看到了这个答案初始化全局数组函数指针在编译时,或运行时main()之前 ,我试着做同样的:

Makefile文件

 ccflags-y := -Wl,-Tlinkerscript.ld obj-m += hello-1.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

linkerscript.ld

 SECTIONS { .rel.rodata.counters : { PROVIDE(start_counters = .); *(counters) PROVIDE(stop_counters = .); } } INSERT AFTER .text; 

但我不断收到相同的警告。 我不确定我是否对链接器脚本做了错误,或者这不是我的问题的解决scheme。

编辑:

我在编辑我的问题,希望有人能给我一个解决方法。 在编译时,声明几个结构体并填充数据。 每个结构都是在块中声明的,所以我不能通过名字来访问它们,我不能在外面声明它们。 我也不知道结构的确切数目,因为它可以从编译到编译。 我需要的是一种方法来访问它们(遍历它们)。 我实际上并不在乎这些结构是否会被保存在一个部分或者其他一些魔法中,只要我可以遍历它们。

这适用于我:

Makefile文件

 obj-m := example.o example-y += hello.o ldflags-y += -T$(M)/layout.lds all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

layout.lds

 SECTIONS { .counters : { __start_counters = . ; *(.counters) __stop_counters = . ; } } 

你好ç

 #include <linux/module.h> #include <linux/kernel.h> char a, b, c; asm (".section .counters, \"aw\""); typedef struct { int counter; char *name; } __attribute__((packed)) counter_info_t; #define __PUT_STUFF_IN_SECTION(_name) \ do{ \ static counter_info_t __counter_info_##_name \ __attribute((unused,section(".counters"))) = { \ .name = #_name, \ .counter = 0, \ }; \ }while(0) extern counter_info_t __start_counters[]; extern counter_info_t __stop_counters[]; int init_module(void){ __PUT_STUFF_IN_SECTION(a); __PUT_STUFF_IN_SECTION(b); __PUT_STUFF_IN_SECTION(c); return 0; } void cleanup_module(void){ counter_info_t *iter = __start_counters; for(; iter < __stop_counters; ++iter){ printk(KERN_INFO "Name: %s | Counter: %d.\n", iter->name, iter->counter); } 

}

重点是使用ldflags-y变量。

为了解决在不同的代码块中定义结构的需求,这些代码块的数量可以变化,而且不能集中引用它们,所以想到两个想法。 首先,下面将要介绍的是使用注册方法,其次是构建过程扫描这些结构的源以收集它们的信息,以便创建具有必要参考的新源文件。

注册方法

  • 使用链表来保存已注册的结构
  • 在创建每个结构时,调用一个函数来注册它; 一个宏是简化语法并允许该方法相对容易改变的好选择。

例如:

 struct reg_list_node { struct counter_info *counter; struct reg_list_node *next }; void register_counter (counter_info *new_counter) { // intentionally leaving out detail; allocate the new node and insert into the list } #define REGISTER_COUNTER(counter) register_counter(&counter) 

那么,当柜台登记时:

 struct counter_info my_counter; REGISTER_COUNTER(my_counter); 

哦,这样就不需要动态分配(请注意宏的语法 – 它可能需要tweeking):

 struct reg_list_node { struct counter_info *counter; struct reg_list_node *next } head; void register_counter (reg_list_node *new_node) { new_node->next = head; head = new_node; } #define REGISTER_COUNTER(cntr) { static struct reg_list_node counter_node; counter_node.counter = & cntr; register_counter(&counter_node); }