2013-09-07 13 views
5

私はカスタムセクションにいくつかの構造体を保存し、それらの構造体を反復して内容を表示するCでこのPOCを持っています。LKMのELFセクションを使用

#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内部のセクション属性を使用することが出来るのですか?

EDIT:

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; 

が、私は同じことを得続ける:私はこの答えInitialize global array of function pointers at either compile-time, or run-time before main()を見て、私は同じことをやってみました

警告。私はリンカスクリプトに何か問題があったかどうか、私の問題の解決策ではないかどうかは分かりません。

EDIT:

私はそううまくいけば、誰かが私に回避策を与えることができ、私の質問を編集しています。コンパイル時に、いくつかの構造体が宣言され、データで埋められます。各構造体はブロック内で宣言されているので、名前でアクセスすることはできません。外に宣言することはできません。私はまた、コンパイルからコンパイルに変わる可能性のある構造体の正確な数を知らない。私が必要とするのは、それらすべてにアクセスする(それらを繰り返し実行する)方法です。構造体がセクションに保存されるか、他の魔法と一緒に保存されるかどうかは、実際には気にしません。

+0

カーネルモジュールの例では、このような( ".name = #_name")のような前処理を使用していますが、このような使用を試みています( "__start_counters;")。これを行うには、これを元に戻す必要があります( "__counters_start")。 –

+0

@PeterL。 '' '.name'''はセクション名とは関係ありません。 '' '.name''は構造体' '' counter_info''の単なる項目です。つまり、私のリンカスクリプトで '' '' start_counter'''にある単語を切り替えるべきだと思いますか? – alexandernst

+0

おそらくカーネルローダーはこの属性をサポートしていません。カーネルモジュールの読み込みとプログラムの違いの1つは、前者が動的にカーネルにコードを追加していることです。新しいセクションを追加するのは遅すぎると思われます。 – ash

答えて

5

これは動作します私のために:

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

のhello.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変数を使用することです。

+0

私はこれをProcmonでテストします。すべてが期待通りに機能します:)素晴らしい作業です! – alexandernst

+0

@alexandernst:それはあなたの仕事です:) –

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); } 
+0

+1。これは実際には全く悪い考えではありません。私が家に帰るときにそれを試してみましょう;) – alexandernst

+0

クール。私はそれがうまくいくことを望む。 – ash

関連する問題