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 属性を使用するにはどうすればよいですか?

編集:

私はこの答えを見ましたコンパイル時、または 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

linkerscript.ld

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 = . ;
    }
}

こんにちはC

#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

コードのさまざまなブロックで定義された構造体をキャプチャする必要性を解決するために、それらの数が異なる可能性があり、それらへの参照を一元化できない場合、2 つのアイデアが思い浮かびます。1 つ目は、以下で説明するように、登録方法を使用することです。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);

ああ、これで動的割り当ての必要がなくなります (マクロの構文に注意してください - 微調整が必​​要な場合があります)。

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 に答える