usuario son sistema seguridad modo llamadas llamada lista las interfaz funciona como c module kernel symbol-table

son - ¿Cómo llamar a las funciones del módulo del kernel exportado desde otro módulo?



llamadas al sistema en windows (3)

De mi investigación, parece que esas son las únicas tres formas de manejar esta situación, y he conseguido que cada una de ellas funcione, así que creo que simplemente elegiré mi favorita de esas.

Estoy escribiendo una API como un módulo del kernel que proporciona controladores de dispositivos con varias funciones. Escribí tres funciones en mycode.c . Luego construí y cargué el módulo, luego copié mycode.h en <kernel> / include / linux . En un controlador de dispositivo, tengo un #include <linux / mycode.h> y llamo a esas tres funciones. Pero cuando construyo el módulo del controlador, recibo tres advertencias de vinculador que dicen que esas funciones no están definidas .

Notas:

  • Las funciones se declaran extern en mycode.h
  • Las funciones se exportan usando EXPORT_SYMBOL (func_name) en mycode.c
  • Ejecutar el comando nm mycode.ko muestra que las tres funciones están disponibles en la tabla de símbolos (con la T mayúscula junto a ellas, lo que significa que los símbolos se encuentran en la sección de texto (código))
  • Después de cargar el módulo, el comando grep func_name / proc / kallsyms muestra las tres funciones como cargadas

Así que claramente las funciones se están exportando correctamente y el kernel sabe qué y dónde están. Entonces, ¿por qué el conductor no puede ver sus definiciones? ¿Alguna idea de lo que me estoy perdiendo?

EDITAR: He encontrado información sobre esto aquí: http://www.kernel.org/doc/Documentation/kbuild/modules.txt

A veces, un módulo externo utiliza símbolos exportados desde otro módulo externo. kbuild necesita tener un conocimiento completo de todos los símbolos para evitar escupir advertencias sobre símbolos no definidos. Existen tres soluciones para esta situación.

NOTA: Se recomienda el método con un archivo kbuild de nivel superior, pero puede ser poco práctico en ciertas situaciones.

Use un archivo kbuild de nivel superior Si tiene dos módulos, foo.ko y bar.ko, donde foo.ko necesita símbolos de bar.ko, puede usar un archivo kbuild de nivel superior común para que ambos módulos se compilen de la misma construir. Considere el siguiente diseño de directorio:

./foo/ <= contains foo.ko ./bar/ <= contains bar.ko The top-level kbuild file would then look like: #./Kbuild (or ./Makefile): obj-y := foo/ bar/ And executing $ make -C $KDIR M=$PWD will then do the expected and compile both modules with full

Conocimiento de los símbolos de cualquiera de los módulos.

Use un archivo extra Module.symvers Cuando se construye un módulo externo, se genera un archivo Module.symvers que contiene todos los símbolos exportados que no están definidos en el núcleo. Para obtener acceso a los símbolos desde bar.ko, copie el archivo Module.symvers de la compilación de bar.ko al directorio donde se construye foo.ko. Durante la creación del módulo, kbuild leerá el archivo Module.symvers en el directorio del módulo externo y, cuando finalice la creación, se creará un nuevo archivo Module.symvers que contiene la suma de todos los símbolos definidos y no forma parte del núcleo.

Use la variable "make" KBUILD_EXTRA_SYMBOLS Si no es práctico copiar Module.symvers desde otro módulo, puede asignar una lista de archivos separados por espacios a KBUILD_EXTRA_SYMBOLS en su archivo de compilación. Estos archivos serán cargados por modpost durante la inicialización de sus tablas de símbolos.

Pero con estas tres soluciones, para que cualquier controlador use mi API, ¿tendría que crear un nuevo Makefile o tener acceso directo a mi archivo Module.symvers? Eso parece un poco inconveniente. Esperaba que pudieran simplemente # incluir mi archivo de encabezado y estar listos para salir. ¿No existen otras alternativas?


OK: tiene un módulo donde está la función y un lugar, ¿qué quiere importarla correctamente?

Debe usar "EXPORT_SYMBOL (" nombre de la función ") como foo en el lugar donde se encuentra la función. En el archivo" c ", la función" foo "está definida y colocada en: EXPORT_SYMBOL (foo)

Asegúrese de tener el prototipo para "foo" en un archivo de encabezado común (puede tenerlo en lugares separados para cada módulo y funcionará, pero está pidiendo problemas si las firmas cambian). Así que di: void foo (void * arg);

Luego el otro módulo que lo quiere simplemente invoca "foo" y eres bueno.

También: asegúrese de cargar el módulo con foo primero. Si tiene dependencias cruzadas como, por ejemplo, el módulo2 necesita foo del módulo1 y el módulo1 necesita la barra del módulo2, debe tener una función de registro con otra. Si quieres saberlo por favor pregunta por separado.


Ejemplo de QEMU + Buildroot mínimo

He probado lo siguiente en un entorno QEMU + Buildroot completamente reproducible, por lo que tal vez tener esta versión de trabajo le ayude a descubrir qué está pasando con su código.

GitHub upstream se centra en los archivos: dep.c | dep2.c | Makefile

dep.c:

#include <linux/delay.h> /* usleep_range */ #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/module.h> MODULE_LICENSE("GPL"); int lkmc_dep = 0; EXPORT_SYMBOL(lkmc_dep); static struct task_struct *kthread; static int work_func(void *data) { while (!kthread_should_stop()) { printk(KERN_INFO "%d/n", lkmc_dep); usleep_range(1000000, 1000001); } return 0; } static int myinit(void) { kthread = kthread_create(work_func, NULL, "mykthread"); wake_up_process(kthread); return 0; } static void myexit(void) { kthread_stop(kthread); } module_init(myinit) module_exit(myexit)

dep2.c:

#include <linux/delay.h> /* usleep_range */ #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/module.h> MODULE_LICENSE("GPL"); extern int lkmc_dep; static struct task_struct *kthread; static int work_func(void *data) { while (!kthread_should_stop()) { usleep_range(1000000, 1000001); lkmc_dep++; } return 0; } static int myinit(void) { kthread = kthread_create(work_func, NULL, "mykthread"); wake_up_process(kthread); return 0; } static void myexit(void) { kthread_stop(kthread); } module_init(myinit) module_exit(myexit)

Ahora puedes hacer lo siguiente:

insmod dep.ko insmod dep2.ko

pero Buildroot también ya está configurando depmod /lib/module/*/depmod con la dependencia, así que solo esto es suficiente para cargar ambos:

modprobe dep

Si usa CONFIG_KALLSYMS_ALL=y , entonces el símbolo se puede ver con:

grep lkmc_dep /proc/kallsyms

vea también: ¿Kallsyms tiene todos los símbolos de las funciones del kernel?