Faedah memperkenalkan mekanisme modul dalam Linux: 1. Apabila aplikasi keluar, ia boleh mengabaikan pelepasan sumber atau kerja pembersihan lain, tetapi fungsi keluar modul mesti membuat asal dengan berhati-hati semua yang dilakukan oleh permulaan fungsi; 2 , Mekanisme ini membantu memendekkan kitaran pembangunan modul, iaitu, pendaftaran dan penyahpasangan adalah sangat fleksibel dan mudah.
Persekitaran pengendalian tutorial ini: sistem linux7.3, komputer Dell G3.
Mula-mula, modul pradaftar sendiri untuk menyampaikan permintaan masa hadapan, dan kemudian fungsi permulaannya tamat serta-merta. Dalam erti kata lain, tugas fungsi permulaan modul adalah untuk menyediakan lebih awal untuk panggilan fungsi masa hadapan.
Faedah:
1) Apabila aplikasi keluar, ia boleh mengabaikan pelepasan sumber atau kerja pembersihan lain, tetapi fungsi keluar modul mesti membatalkan dengan teliti pemulaan Semua yang dilakukan oleh fungsi.
2) Mekanisme ini membantu memendekkan kitaran pembangunan modul. Iaitu: pendaftaran dan nyahpasang adalah sangat fleksibel dan mudah.
Linux membenarkan pengguna campur tangan dalam kernel dengan memasukkan modul. Mekanisme modul Linux tidak begitu jelas untuk masa yang lama, jadi artikel ini menganalisis secara ringkas mekanisme pemuatan modul kernel.
Helo Dunia modul!
Kami menguji dengan mencipta modul mudah. Yang pertama ialah fail sumber main.c dan Makefile.
florian@florian-pc:~/module$ cat main.c
#include<linux/module.h> #include<linux/init.h> static int __init init(void) { printk("Hi module!\n"); return 0; } static void __exit exit(void) { printk("Bye module!\n"); } module_init(init); module_exit(exit);
di mana init ialah fungsi kemasukan modul, yang dipanggil apabila modul dimuatkan, dan keluar ialah modul keluar fungsi, yang dilaksanakan dalam modul Pemunggahan dipanggil dan dilaksanakan.
florian@florian-pc:~/module$ cat Makefile
obj-m += main.o #generate the path CURRENT_PATH:=$(shell pwd) #the current kernel version number LINUX_KERNEL:=$(shell uname -r) #the absolute path LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL) #complie object all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #clean clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
Antaranya, obj-m menentukan nama fail sasaran, dan nama fail perlu adalah sama dengan nama fail sumber (Kecuali sambungan) untuk memudahkan terbitan automatik dengan membuat.
Kemudian gunakan arahan make untuk menyusun modul dan dapatkan fail modul main.ko.
florian@florian-pc:~/module$ make
make -C /usr/src/linux-headers-2.6.35-22-generic M=/home/florian/module modules make[1]: 正在进入目录 `/usr/src/linux-headers-2.6.35-22-generic' Building modules, stage 2. MODPOST 1 modules make[1]:正在离开目录 `/usr/src/linux-headers-2.6.35-22-generic'
Gunakan perintah insmod dan rmmod untuk memuatkan dan memunggah modul, dan gunakan dmesg untuk mencetak log kernel.
florian@florian-pc:~/module$ sudo insmod main.ko;dmesg | tail -1 [31077.810049] Hi module!
florian@florian-pc:~/module$ sudo rmmod main.ko;dmesg | tail -1 [31078.960442] Bye module!
Melalui maklumat log kernel, ia boleh dilihat bahawa kedua-dua fungsi masuk dan keluar modul telah Betul pelaksanaan panggilan.
Fail modul
Gunakan arahan readelf untuk menyemak maklumat fail modul main.ko.
florian@florian-pc:~/module$ readelf -h main.ko
ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 1120 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 19 Section header string table index: 16
Kami mendapati bahawa jenis fail main.ko ialah fail sasaran yang boleh dipindahkan, yang berbeza daripada sasaran umum format fail. Kami tahu bahawa fail sasaran tidak boleh dilaksanakan secara langsung Ia perlu melalui proses peruntukan ruang alamat, resolusi simbol dan penempatan semula pemaut dan ditukar kepada fail boleh laku sebelum ia boleh dilaksanakan.
Jadi, selepas kernel memuatkan main.ko, adakah ia memautkannya?
Struktur data modul
Pertama, mari kita lihat struktur data kernel modul.
linux3.5.2/kernel/module.h:220
struct module { …… /* Startup function. */ int (*init)(void); …… /* Destruction function. */ void (*exit)(void); …… };
Penunjuk fungsi init dan exit struktur data modul merekodkan fungsi masuk dan keluar modul yang kami takrifkan .
Pemuatan modul
Pemuatan modul diselesaikan dengan panggilan sistem kernel init_module.
linux3.5.2/kernel/module.c:3009
/* This is where the real work happens */ SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs) { struct module *mod; int ret = 0; …… /* Do all the hard work */ mod = load_module(umod, len, uargs);//模块加载 …… /* Start the module */ if (mod->init != NULL) ret = do_one_initcall(mod->init);//模块init函数调用 …… return 0; }
Panggilan sistem init_module dilaksanakan oleh SYSCALL_DEFINE3(init_module...), yang mempunyai dua fungsi utama panggilan. load_module digunakan untuk memuatkan modul, dan do_one_initcall digunakan untuk memanggil semula fungsi init modul.
Pelaksanaan fungsi load_module ialah. Terdapat empat panggilan fungsi utama dalam fungsi load_module. copy_and_check menyalin modul dari ruang pengguna ke ruang kernel, layout_and_allocate memperuntukkan ruang alamat untuk modul, simplify_symbols melaksanakan resolusi simbol untuk modul dan apply_relocations melakukan penempatan semula untuk modul.
linux3.5.2/kernel/module.c:2864
Bagi pelaksanaan fungsi do_one_initcall, ia agak mudah.
/* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, unsigned long len, const char __user *uargs) { struct load_info info = { NULL, }; struct module *mod; long err; …… /* Copy in the blobs from userspace, check they are vaguely sane. */ err = copy_and_check(&info, umod, len, uargs);//拷贝到内核 if (err) return ERR_PTR(err); /* Figure out module layout, and allocate all the memory. */ mod = layout_and_allocate(&info);//地址空间分配 if (IS_ERR(mod)) { err = PTR_ERR(mod); goto free_copy; } …… /* Fix up syms, so that st_value is a pointer to location. */ err = simplify_symbols(mod, &info);//符号解析 if (err < 0) goto free_modinfo; err = apply_relocations(mod, &info);//重定位 if (err < 0) goto free_modinfo; …… }
Iaitu, fungsi kemasukan modul ini dipanggil.
linux3.5.2/kernel/init.c:673
Penyahpasangan modul
int __init_or_module do_one_initcall(initcall_t fn) { int count = preempt_count(); int ret; if (initcall_debug) ret = do_one_initcall_debug(fn); else ret = fn();//调用init module …… return ret; }
Lengkapkan fungsi fungsi eksport modul melalui pintu keluar panggil balik, dan akhirnya panggil free_module untuk menyahpasang modul.
Kesimpulan
Nampaknya modul kernel tidak misteri. Atur cara pengguna tradisional perlu disusun ke dalam atur cara boleh laku sebelum ia boleh dilaksanakan, manakala atur cara modul hanya perlu disusun ke dalam fail objek sebelum ia boleh dimuatkan ke dalam kernel Inti melaksanakan pautan ke modul dan menukarnya kepada kod boleh laku . Pada masa yang sama, semasa proses pemuatan dan pemunggahan kernel, fungsi kemasukan modul yang ditentukan pengguna dan fungsi keluar modul akan dipanggil semula melalui fungsi untuk melaksanakan fungsi yang sepadan.
Cadangan berkaitan: "Tutorial Video Linux"
Atas ialah kandungan terperinci Apakah faedah memperkenalkan mekanisme modul dalam linux?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!