2015-11-15 18 views
12

Tôi đang làm việc trong Ubuntu. Tôi đang cố gắng tạo hai mô-đun hạt nhân sử dụng từng chức năng khác. Vấn đề của tôi là tôi có các mô-đun được biên dịch đúng cách, nhưng biểu tượng không được giải quyết cho một trong số chúng.không thành công không thành công với "Biểu tượng không xác định trong mô-đun" cho biểu tượng được xác định trong một mô-đun khác

Để đơn giản, hãy gọi các mô-đun này là m1m2.

m2 là chức năng xuất void func_m2(void). m1 đang gọi chức năng này. Cả hai mô đun đều biên dịch đúng cách.

Sau khi tất cả biên dịch, tôi cần tải trước mô-đun m2 (vì nó đã xuất func_m2 chức năng) và sau đó là mô-đun m1. Vì vậy, chúng ta hãy làm cho nó:

[email protected]:~/development/kmodules/m2$ sudo insmod ./m2.ko 

Bây giờ, cho phép tải m1 mô-đun mà đang cố gắng sử dụng func_m2:

[email protected]:~/development/kmodules/m1$ sudo insmod ./m1.ko 
insmod: error inserting './m1.ko': -1 Unknown symbol in module 

Sau đây là những gì tôi nhìn thấy trong nhật ký:

[email protected]:~/development/kmodules/m1$ dmesg | tail 
[ 3938.166616] Loading m2 module ... 
[ 3963.078055] m1: no symbol version for func_m2 
[ 3963.078059] m1: Unknown symbol func_m2 

Vì vậy, có vẻ như các tham chiếu đến ký hiệu func_m2 không được giải quyết. Hấp dẫn. Hãy kiểm tra xem nó có trong bảng biểu tượng không:

[email protected]:~/development/kmodules$ cat /proc/kallsyms | grep 'func_m2' 
ffffffffa00530d0 r __ksymtab_func_m2 [m2] 
ffffffffa00530e8 r __kstrtab_func_m2 [m2] 
ffffffffa00530e0 r __kcrctab_func_m2 [m2] 
ffffffffa0053000 T func_m2  [m2] 
000000004edd543f a __crc_func_m2  [m2] 

Như bạn có thể thấy, func_m2 thực sự xuất hiện trong bảng ký hiệu. Vậy tại sao không thể tải được m1?

Tôi đã cài đặt đúng tiêu đề Linux cho nguồn kernel và Linux của mình. Tôi không thực hiện bất kỳ sửa đổi nào trong hạt nhân, nó không bị ảnh hưởng và phiên bản của nó là: 2.6.31-16-generic (Tôi chạy x64)

Bây giờ, để hiển thị cho bạn bức tranh đầy đủ, tôi đặt mã nguồn và Makefile ở đây Tôi đã sử dụng cho thử nghiệm này cho cả hai mô-đun m1m2.

m1 mô-đun:

m1.c:

#include <linux/module.h> 
#include <linux/kernel.h> 

extern void func_m2(void); 

int hello_start(void) 
{ 
    printk(KERN_INFO "Loading m1 module ...\n"); 

    func_m2(); 

    return 0; 
} 

void hello_end(void) 
{ 
    printk(KERN_INFO "Unloading m1 ...\n"); 
} 

module_init(hello_start); 
module_exit(hello_end); 

MODULE_LICENSE("GPL"); 

Makefile:

obj-m := m1.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 

m2 mô-đun:

m2.c:

#include <linux/module.h> 
#include <linux/kernel.h> 

int hello_start(void) 
{ 
    printk(KERN_INFO "Loading m2 module ...\n"); 

    return 0; 
} 

void hello_end(void) 
{ 
    printk(KERN_INFO "Unloading m2 ...\n"); 
} 

void func_m2(void) 
{ 
    printk(KERN_INFO "This a function in m2\n"); 
} 

module_init(hello_start); 
module_exit(hello_end); 

MODULE_LICENSE("GPL"); 
EXPORT_SYMBOL(func_m2); 

Makefile:

obj-m := m2.o 
export-objs := m2.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 

Về cơ bản câu hỏi của tôi là: Tại sao không thể m1 được nạp?

Sẽ rất hữu ích nếu ai đó có thể trả lời.

+0

https://serverfault.com/questions/124128/linux-says-a-kernel-module-has-an-unknown-symbol-but-another-loaded-module-prov –

Trả lời

3

Dưới đây là một số vấn đề tôi thấy với mã của bạn:

(a). Các hàm khởi tạo và kết thúc của bạn phải được khai báo tĩnh và được xác định đúng. Ví dụ, trong m1.c -

static int __init hello_start(void) 
{ 
    printk(KERN_INFO "Loading m1 module ...\n"); 

    func_m2(); 

    return 0; 
} 

static void __exit hello_end(void) 
{ 
    printk(KERN_INFO "Unloading m1 ...\n"); 
} 

Lặp lại điều này cho m2.c

(b). Xây dựng cả hai mô-đun của bạn với nhau, sử dụng cùng một Makefile. Tôi đặt cược nếu bạn nhìn kỹ vào đầu ra từ Makefile hiện tại của bạn cho m1.c, bạn sẽ thấy một cảnh báo chỉ ra rằng func_m2() là không xác định. Nhưng dù sao, các Makefile hợp nhất sẽ giống như thế -

SRCS = m1.c m2.c 
OBJS = $(SRCS:.c=.o) 

obj-m += $(OBJS) 

EXTRA_CFLAGS = -O2 


all: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules 

clean: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean 
    $(RM) Module.markers modules.order 

Sau khi cả hai module được xây dựng, chạy insmod vào 'm2.ko' trước khi phát hành insmod cho 'm1.ko'. Kiểm tra kết quả qua dmesg.

Ngoài ra, ở đây tôi giả định rằng cả hai m1.c và m2.c đều nằm trong cùng một thư mục. Ngay cả khi họ đang ở trong các thư mục khác nhau, kỹ thuật này sẽ làm việc, nhưng nó sẽ được lộn xộn. Nếu chúng nằm trong các thư mục khác nhau, hãy làm như sau.

Tôi đã nghiên cứu rất ít và tìm thấy cách xây dựng mô-đun trong các thư mục riêng biệt. Ví dụ tôi sử dụng đơn giản hơn nhiều so với những gì bạn có, nhưng có lẽ nó có khả năng thích ứng.

Tôi đã sau biểu hiện của tập tin trong một thư mục gọi là ExportSymbol ...

$ ls -CFR 
.: 
include/ Makefile mod1/ mod2/ 

./include: 
m2_func.h 

./mod1: 
Makefile module1.c 

./mod2: 
Makefile module2.c 

Các m2_func.h xuất hiện như:

#ifndef M2_FUNC_H 
#define M2_FUNC_H 

void m2_func(void); 

#endif 

Các Makefile cấp cao nhất xuất hiện như:

obj-y := mod1/ mod2/ 

all: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules 

clean: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean 
    $(RM) Module.markers modules.order 

Các Makefile và module1.c, đó là trong mod1 /, xuất hiện như:

SRCS = module1.c 
OBJS = $(SRCS:.c=.o) 

obj-m += $(OBJS) 

EXTRA_CFLAGS += -I${PWD}/include 

all: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules 

clean: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean 
    $(RM) Module.markers modules.order 

#include <linux/module.h> 
#include <linux/kernel.h> 

static int __init hello_start(void) 
{ 
printk(KERN_INFO "Loading m1 module ...\n"); 

m2_func(); 

return 0; 
} 

static void __exit hello_end(void) 
{ 
printk(KERN_INFO "Unloading m1 ...\n"); 
} 

module_init(hello_start); 
module_exit(hello_end); 

MODULE_LICENSE("GPL"); 

Makefile và module2.c, trong mod2 /, a ppear như:

SRCS = module2.c 
OBJS = $(SRCS:.c=.o) 

obj-m += $(OBJS) 

EXTRA_CFLAGS += -I${PWD}/include 

all: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules 

clean: 
    $(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean 
    $(RM) Module.markers modules.order 

#include "m2_func.h" 
#include <linux/module.h> 
#include <linux/kernel.h> 

static int __init hello_start(void) 
{ 
printk(KERN_INFO "Loading m2 module ...\n"); 

return 0; 
} 

static void __exit hello_end(void) 
{ 
printk(KERN_INFO "Unloading m2 ...\n"); 
} 

void m2_func(void) 
{ 
printk(KERN_INFO "This a function in m2\n"); 
} 

module_init(hello_start); 
module_exit(hello_end); 

MODULE_LICENSE("GPL"); 
EXPORT_SYMBOL(m2_func); 

LƯU Ý: tôi không thể sử dụng makefile của bạn vì nó tạo ra * .ko cho mỗi tập tin c. Makefile đang thực hiện công việc của mình. Tệp 'ko' là tệp đối tượng hạt nhân; bạn sẽ có một tệp cho mỗi tệp .c nguồn. Không có cách nào xung quanh chuyện này. Nếu bạn không muốn nhiều tập tin ko, sau đó đặt tất cả các mã của bạn trong một tập tin nguồn.

+0

Theo tôi, có một cách để tạo nhiều tệp C và không tạo nhiều tệp .ko. Tôi nhớ tôi đã tạo nhiều tệp .c trong dự án cũ nhưng chỉ có một tệp .ko. Cảm ơn câu trả lời bằng cách này. –

4

Khi bạn tạo m2, nó sẽ tạo một tệp Module.symvers.

Sao chép tệp này vào nơi bạn đang xây dựng m1. Sau đó, làm cho m1, và insmod nó.

Bạn có thể đã có một cảnh báo khi bạn đang xây dựng m1 trước đó, một cái gì đó như:

CẢNH BÁO: "func_m2" [/tmp/m1/m1.ko] undefined!

Điều này sẽ biến mất khi bạn sử dụng Module.symvers từ mô-đun m2.

Từ http://www.kernel.org/doc/Documentation/kbuild/modules.txt:

--- 6.2 Các ký hiệu và Modules ngoài

Khi xây dựng một mô-đun bên ngoài, xây dựng hệ thống cần truy cập để những biểu tượng từ hạt nhân để kiểm tra xem tất cả các biểu tượng bên ngoài được định nghia. Điều này được thực hiện trong bước MODPOST. modpost có được các ký hiệu bằng cách đọc Module.symvers từ nguồn kernel . Nếu tệp Module.symvers có trong thư mục nơi mô-đun bên ngoài đang được xây dựng, tệp này sẽ là cũng đọc. Trong bước MODPOST, một tệp Module.symvers mới sẽ được viết có chứa tất cả các ký hiệu đã xuất không phải là được định nghĩa trong hạt nhân.

Và điều này cũng rất đáng đọc, so với cùng file:

--- 6.3 Biểu tượng Từ khác Mô-đun bên ngoài

Đôi khi, một mô-đun bên ngoài sử dụng những biểu tượng xuất khẩu từ khác mô-đun bên ngoài . kbuild cần phải có kiến ​​thức đầy đủ về tất cả các ký hiệu để tránh phát tán cảnh báo về các ký hiệu không được xác định . Ba giải pháp tồn tại cho tình huống này.

LƯU Ý: Phương pháp có tệp kbuild cấp cao nhất được đề xuất nhưng có thể không thực tế trong một số trường hợp nhất định.

Sử dụng một top-level kbuild tập tin Nếu bạn có hai mô-đun, foo.ko và bar.ko, nơi foo.ko cần biểu tượng từ bar.ko, bạn có thể sử dụng chung một file kbuild cấp cao nhất để cả hai mô-đun là được biên dịch trong cùng một bản dựng. Xem xét bố trí thư mục sau:

./foo/ < = chứa foo.ko ./bar/ < = chứa bar.ko

File kbuild cấp cao nhất sau đó sẽ như thế nào:

$ ./Kbuild (hoặc./ Makefile): obj-y: = foo/bar/

Và thực

$ make -C $ KDIR M = $ PWD

sẽ thì đừng mong đợi và biên dịch cả hai mô-đun với đầy đủ kiến thức về các biểu tượng từ một trong hai mô-đun.

Sử dụng một Module.symvers thêm nộp Khi một module bên ngoài được xây dựng, một Module.symvers nộp được tạo ra chứa tất cả những biểu tượng xuất khẩu mà là không được định nghĩa trong kernel. Để truy cập vào các ký hiệu từ bar.ko, hãy sao chép tệp Mô-đun từ tệp biên soạn của bar.ko vào thư mục nơi foo.ko được xây dựng . Trong quá trình xây dựng mô-đun, kbuild sẽ đọc tệp Module.symvers trong thư mục của mô-đun bên ngoài và khi xây dựng xong, tệp Module.symvers mới được tạo có chứa tổng là tất cả các ký hiệu được xác định và không phải là một phần của hạt nhân.

Sử dụng "làm cho" KBUILD_EXTRA_SYMBOLS biến Nếu đó là không thực tế để sao chép Module.symvers từ mô-đun khác, bạn có thể gán một không gian tách biệt danh sách các tập tin để KBUILD_EXTRA_SYMBOLS trong xây dựng tập tin của bạn. Những tệp này sẽ được tải bằng modpost trong khi khởi tạo các bảng biểu tượng của nó.

Các vấn đề liên quan