5

我在 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.

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

你好-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);
    }

}

生成文件:

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 属性?

编辑:

我看到了这个答案Initialize global array of function pointers at either compile-time, or run-time before main()我试着做同样的事情:

生成文件

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

链接脚本文件

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

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

编辑:

我正在编辑我的问题,希望有人能给我一个解决方法。在编译时,会声明一些结构并用数据填充。每个结构都在一个块中声明,因此我不能按名称访问它们,也不能在外面声明它们。我也不知道结构的确切数量,因为它可以从编译变为编译。我需要的是一种访问它们的方法(迭代它们)。我实际上不在乎这些结构是要保存在一个部分中还是使用其他一些魔法,只要我可以迭代它们。

4

2 回答 2

5

这对我有用:

生成文件

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

布局.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变量。

于 2013-09-10T15:14:57.123 回答
2

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

报名方式

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

例如:

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); }
于 2013-09-10T14:23:04.620 回答