2013-09-07 68 views
5

Tôi có POC này trong C để lưu một vài cấu trúc trong phần tùy chỉnh và sau đó lặp lại trên các cấu trúc đó, hiển thị nội dung của chúng.Sử dụng phần ELF trong LKM

#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; 
} 

Output:

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

Kết quả được như mong đợi, vì vậy tôi đang cố gắng để làm điều đó điều tương tự trong một mô-đun hạt nhân:

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 

Nhưng tôi nhận được những cảnh báo khi tôi biên dịch các module:

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! 

Câu hỏi của tôi là: Tại sao không được làm việc và làm thế nào tôi phải sử dụng phần thuộc tính bên trong một LKM?

EDIT:

Tôi thấy câu trả lời này Initialize global array of function pointers at either compile-time, or run-time before main() và tôi đã cố gắng làm như vậy:

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; 

nhưng tôi tiếp tục nhận được cùng cảnh báo. Tôi không chắc chắn nếu tôi đã làm điều gì đó sai trái với kịch bản liên kết hoặc đó không chỉ là giải pháp cho vấn đề của tôi.

EDIT:

Tôi đang chỉnh sửa câu hỏi của mình để hy vọng ai đó có thể giải quyết cho tôi. Tại thời gian biên dịch, một vài cấu trúc được khai báo và chứa đầy dữ liệu. Mỗi cấu trúc được khai báo trong một khối vì vậy tôi không thể truy cập chúng theo tên và tôi không thể khai báo chúng bên ngoài. Tôi cũng không biết chính xác số lượng cấu trúc vì nó có thể thay đổi từ biên dịch thành biên dịch. Những gì tôi cần là một cách để truy cập tất cả chúng (lặp qua chúng). Tôi thực sự không quan tâm nếu các cấu trúc sẽ được lưu trong một phần hoặc với một số phép thuật khác, theo như tôi có thể lặp lại chúng.

+0

Trong ví dụ mô-đun hạt nhân của bạn, bạn đang sử dụng bộ tiền xử lý đính kèm như thế này (".name = #_name"), nhưng cố gắng sử dụng chúng như thế này ("__start_counters;"). Bạn sẽ phải đảo ngược nó để làm việc này ("__counters_start"). –

+0

@PeterL. '' '.name''' không liên quan gì đến tên phần. '' '.name''' chỉ là một mục của struct' '' counter_info'''. Điều đó nói rằng, bạn có nghĩ rằng tôi nên chuyển đổi từ trong '' 'start_counter''' trong kịch bản linker của tôi? – alexandernst

+0

Có lẽ trình tải hạt nhân không hỗ trợ thuộc tính này. Một sự khác biệt giữa tải mô-đun hạt nhân và chương trình là trước đây là tự động thêm mã vào hạt nhân đang chạy, vì vậy tôi nghi ngờ đã quá trễ để thêm các phần mới. – ash

Trả lời

5

Công trình này cho tôi:

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

}

Vấn đề là sử dụng biến số ldflags-y.

+0

Tôi thử nghiệm điều này trong Procmon, mọi thứ hoạt động như mong đợi :) Công việc tuyệt vời! – alexandernst

+0

@alexandernst: Đó là công việc của bạn :) –

2

Để giải quyết nhu cầu nắm bắt cấu trúc được xác định trong các khối mã khác nhau nơi số của chúng có thể thay đổi và tham chiếu đến chúng không thể tập trung được, hai ý tưởng sẽ được lưu ý. Đầu tiên, sẽ được mô tả dưới đây, là sử dụng phương thức đăng ký, và thứ hai là có quá trình xây dựng quét các nguồn cho các cấu trúc này để thu thập thông tin của chúng nhằm tạo ra một tệp nguồn mới với các tham chiếu cần thiết.

Đăng ký doanh nghiệp Phương pháp

  • Sử dụng một danh sách liên kết để giữ cấu trúc đăng ký
  • On tạo mỗi struct, hãy gọi một chức năng để đăng ký nó; macro là một lựa chọn tốt để đơn giản hóa cú pháp và cho phép phương thức thay đổi tương đối dễ dàng.

Ví dụ:

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) 

Sau đó, khi các quầy đăng ký:

struct counter_info my_counter; 
REGISTER_COUNTER(my_counter); 

Oh, và điều này giúp loại bỏ sự cần thiết để phân bổ động (xin xem cú pháp của vĩ mô - nó có thể cần 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); } 
+0

+1. Đây thực sự không phải là một ý tưởng tồi chút nào. Hãy để tôi kiểm tra nó khi tôi về nhà;) – alexandernst

+0

Cool. Tôi hy vọng nó hoạt động. – ash