¿Cómo agregar una llamada al sistema en el kernel de Linux?
1. Agregar llamadas al sistema en Linux0.11:\x0d\\x0d\Agregué una nueva llamada al sistema al kernel Linux0.11 en bochs2.2.1. Los pasos son los siguientes: \x0d\1. Agregue /usr/src/linux/include/unistd.h: #define __NR_mytest 87 \x0d\Luego declare el prototipo de función a continuación: int mytest(); / Agregue sys.h: extern int sys_mytest(); \x0d\Luego agregue sys_mytest al final de sys_call_table; agregue la función en /usr/src/linux/kernel/sys.c de la siguiente manera: \ x0d \int sys_mytest(){ \x0d\printk("¡Esto es una prueba!"); \x0d\return 123; \x0d\} \x0d\4. 1 al número de llamada del sistema (originalmente cambiado de 86 a 87) \x0d\5. Luego vaya al directorio /usr/src/linux para compilar la imagen del kernel \x0d\6. linux/include /unistd.h /usr/include/unistd.h \x0d\7. reset bochs \x0d\8 Genere el archivo test.c en /usr/root de la siguiente manera: \x0d\#define __LIBRARY__ \x0d\. #include \x0d \_syscall0(int, miprueba) \x0d\int main(){ \x0d\int a; \x0d\a = miprueba(); 0; \x0d \} \x0d\9. Luego compile gcc test.c y ejecute a.out. Se pasaron todos los pasos anteriores, pero cada llamada devuelve -1. permitido), y luego ¿No sabes por qué? \x0d\ Si algún experto que conozca el sistema puede decirme, ¡estaría muy agradecido! ¡Este problema me ha preocupado durante mucho tiempo! \x0d\\x0d\ 2. Agregar llamadas al sistema al nuevo kernel de Linux \x0d\\x0d\ Cómo agregar nuevas llamadas al sistema en el sistema Linux \x0d\ La llamada al sistema es la interfaz funcional entre la aplicación y el kernel del sistema operativo . Su objetivo principal es permitir a los usuarios utilizar las funciones proporcionadas por el sistema operativo en términos de administración de dispositivos, sistema de entrada/salida, sistema de archivos y control de procesos, comunicación y administración de almacenamiento sin tener que comprender la estructura interna del programa del sistema y detalles de hardware relacionados, por lo que desempeña el papel de reducir la carga del usuario, proteger el sistema y mejorar la utilización de los recursos. \x0d\\x0d\ Como representante del software libre, el excelente rendimiento del sistema operativo Linux ha hecho que su aplicación esté cada vez más extendida. No sólo ha sido reconocido por los profesionales, sino que sus aplicaciones comerciales también están en pleno apogeo. En Linux, la mayoría de las llamadas al sistema están incluidas en la biblioteca libc de Linux, y estas llamadas al sistema se pueden llamar a través del método de llamada de función estándar de C. Entonces, para los entusiastas de Linux, ¿cómo agregar nuevas llamadas al sistema en Linux? \x0d\ 1 Mecanismo de llamada al sistema Linux \x0d\\x0d\ En los sistemas Linux, las llamadas al sistema se implementan como un tipo de excepción. Ejecutará las instrucciones de código de máquina correspondientes para generar la señal de excepción.
El efecto importante de una interrupción o excepción es que el sistema cambia automáticamente del modo de usuario al modo central para procesarla. Esto significa que cuando se ejecuta una instrucción de excepción de llamada al sistema, el sistema cambia automáticamente al estado central y se organiza la ejecución del controlador de excepciones. La instrucción real utilizada por Linux para implementar excepciones de llamadas al sistema es: \x0d\\x0d\ Int $0x80\x0d\\x0d\ Kernel. Para lograr el objetivo de no tener que utilizar programación de instrucciones de máquina cuando se utilizan llamadas al sistema, se proporciona una breve subrutina para cada llamada del sistema en la biblioteca de lenguaje C estándar para completar el trabajo de programación del código de máquina. De hecho, el fragmento de código de máquina es muy breve. Todo lo que tiene que hacer es cargar los parámetros enviados a la llamada al sistema en el registro de la CPU y luego ejecutar la instrucción int $0x80. Luego ejecute la llamada al sistema y el valor de retorno de la llamada al sistema se enviará a un registro de la CPU. La subrutina de biblioteca estándar obtiene el valor de retorno y lo envía de regreso al programa de usuario. \x0d\\x0d\ Para hacer que la ejecución de llamadas al sistema sea una tarea sencilla, Linux proporciona un conjunto de macros de preprocesamiento. Se pueden utilizar en programas. Estas macroinstrucciones toman ciertos parámetros y luego se expanden para llamar a la función de llamada del sistema especificada. \x0d\\x0d\ Estas instrucciones de macro tienen un formato de nombre similar al siguiente: \x0d\\x0d\ reemplazar. Estos parámetros permiten que la macro se expanda para adaptarse a una llamada al sistema particular. Por ejemplo, para crear una función que llame a la llamada al sistema setuid(), debe usar:\x0d\\x0d\ _syscall1(int, setuid, uid_t, uid)\x0d\\x0d\ Int descripción del primer parámetro del macro syscallN () El tipo de valor de retorno de la función generada es un número entero y el segundo parámetro setuid indica el nombre de la función generada. A continuación se detallan cada parámetro requerido por la llamada al sistema. Hay dos parámetros después de esta macro instrucción, uid_t y uid, que se utilizan para especificar el tipo y el nombre de los parámetros respectivamente. \x0d\\x0d\ Además, existe un límite en los tipos de datos utilizados como parámetros para las llamadas al sistema. Su capacidad no puede exceder los cuatro bytes. Esto se debe a que al ejecutar la instrucción int $0x80 para realizar una llamada al sistema, todos los valores de los parámetros se almacenan en registros de CPU de 32 bits. Otra limitación impuesta por el uso de registros de CPU para pasar argumentos es la cantidad de argumentos que se pueden pasar a una llamada al sistema. El límite es que se pueden pasar un máximo de 5 parámetros. Por lo tanto, Linux ha definido 6 instrucciones macro _syscallN() diferentes, desde _syscall0(), _syscall1() hasta _syscall5(). \x0d\\x0d\ Una vez que la macro _syscallN() se expande con los parámetros correspondientes de una llamada al sistema específica, el resultado es una función con el mismo nombre que la llamada al sistema, que puede ejecutar esta llamada al sistema en el programa de usuario. \x0d\ 2 Agregar una nueva llamada al sistema \x0d\ Si el usuario agrega una nueva llamada al sistema en Linux, debe seguir varios pasos para agregarla exitosamente. Los siguientes pasos describen en detalle el contenido relevante de agregar una llamada al sistema. \x0d\\x0d\ (1) Agregar código fuente\x0d\\x0d\ La primera tarea es escribir el programa fuente que se agregará al kernel, que es una función que se agregará a un archivo del kernel. La función debe ser ¿Es el nuevo nombre de llamada al sistema precedido por el indicador sys_?
Supongamos que la llamada al sistema recién agregada es mycall(int number), agregue el código fuente en el archivo /usr/src/linux/kernel/sys.c, como se muestra a continuación: \x0d\ asmlinkage int sys_mycall(int number) \x0d \ { \x0d\ Devuelve número; \x0d\ }\x0d\ Como ejemplo más simple, nuestra nueva llamada al sistema solo devuelve un valor entero. \x0d\\x0d\ (2) Conecte la nueva llamada al sistema \x0d\\x0d\ Después de agregar la nueva llamada al sistema, la siguiente tarea es hacer que el resto del kernel de Linux conozca la existencia del programa. Para agregar enlaces a nuevas funciones de programas del kernel existentes, es necesario editar dos archivos. \x0d\\x0d\ En la versión del kernel de Linux que estamos usando (RedHat 6.0, el kernel es 2.2.5-15), el primer archivo que se modificará es: \x0d\\x0d\ /usr/src/linux/include / asm-i386/unistd.h\x0d\\x0d\ Este archivo contiene una lista de llamadas al sistema y se utiliza para asignar un número único a cada llamada al sistema. El formato de cada línea en el archivo es el siguiente:\x0d\\x0d\ #define __NR_name NNN\x0d\\x0d\ Entre ellos, el nombre se reemplaza por el nombre de la llamada del sistema y NNN es el número correspondiente a la llamada del sistema. . El nuevo nombre de llamada del sistema debe agregarse al final de la lista y asignarse el siguiente número de llamada del sistema disponible en la secuencia numérica. Nuestra llamada al sistema es la siguiente:\x0d\\x0d\ #define __NR_mycall 191\x0d\\x0d\ El número de llamada del sistema es 191. La razón por la cual el número de llamada del sistema es 191 es porque el número de llamada del sistema Linux-2.2 El propio kernel se ha utilizado 190. \x0d\\x0d\ El segundo archivo a modificar es: \x0d\\x0d\ /usr/src/linux/arch/i386/kernel/entry.S\x0d\\x0d\ Lista:\x0d\ .long SYMBOL_NAME ()\x0d\\x0d\ Esta lista se utiliza para inicializar la matriz sys_call_table[]. Esta matriz contiene punteros a cada llamada al sistema en el kernel. Esto agrega el nuevo puntero de función del núcleo a la matriz. Agregamos una línea al final de la lista: \x0d\ .long SYMBOL_NAME(sys_mycall)\x0d\x0d\ (3) Reconstruir el nuevo kernel de Linux \x0d\x0d\ Para que la nueva llamada al sistema surta efecto, el Es necesario reconstruir el kernel de Linux. Esto requiere iniciar sesión como superusuario. \x0d\ #pwd \x0d\ /usr/src/linux \x0d\ #\x0d\\x0d\ El superusuario puede reconstruir el kernel sólo en el directorio de trabajo actual (/usr/src/linux). \x0d\\x0d\ #make config \x0d\ #make dep \x0d\ #make clearn \x0d\ #make bzImage\x0d\\x0d\ Después de la compilación, el sistema genera una imagen del kernel comprimida que se puede usar para la instalación Archivo :\x0d\\x0d\ /usr/src/linux/arch/i386/boot/bzImage \x0d\ (4) Arrancar el sistema con un nuevo kernel\x0d\ Para usar la nueva llamada al sistema, necesita usar un kernel reconstruido nuevo kernel Reinicie el sistema.
Para hacer esto, necesita modificar el archivo /etc/lilo.conf. En nuestro sistema, el contenido del archivo es el siguiente: \x0d\\x0d\boot=/dev/hda \x0d\ Map=/boot/. map \x0d\ install= /boot/boot.b \x0d\ símbolo \x0d\ timeout=50 \x0d\\x0d\ image=/boot/vmlinuz-2.2.5-15 \x0d\ label=linux \x0d\ root =/dev/hdb1 \ x0d\ de solo lectura \x0d\\x0d\ other=/dev/hda1 \x0d\ label=dos \x0d\ table=/dev/had\x0d\x0d\ Primero edite el archivo y agregue un nuevo kernel de arranque:\ x0d\ Image=/boot/bzImage-new \x0d\ label=linux-new \x0d\ root=/dev/hdb1 \x0d\ read-only\x0d\x0d\ Una vez completada la adición, el El contenido del archivo es el siguiente:\ x0d\ boot=/dev/hda \x0d\ map=/boot/map \x0d\ install=/boot/boot.b \x0d\ Prompt \x0d\ timeout=50 \x0d\ \x0d\ image=/boot/bzImage -new \x0d\ Label=linux-new \x0d\ root=/dev/hdb1 \x0d\ de solo lectura \x0d\\x0d\ image=/boot/vmlinuz-2.2.5 -15 \x0d\ label=linux \ x0d\ root=/dev/hdb1 \x0d\ solo lectura \x0d\\x0d\ other=/dev/hda1 \x0d\ label=dos \x0d\ table=/dev/hda \x0d\\x0d\ De esta manera, new La imagen del kernel bzImage-new se convierte en el kernel de arranque predeterminado. Para utilizar el nuevo archivo de configuración lilo.conf, también debe ejecutar el siguiente comando:\x0d\ #cp /usr/src/linux/arch/i386/boot/zImage /boot/bzImage-new\x0d\\x0d \ Segunda configuración lilo:\x0d\\x0d\ #/sbin/lilo\x0d\\x0d\ Ahora, al reiniciar el sistema, hay tres opciones después del inicio: indicador: linux-new, linux, dos y the new kernel se convierte en el kernel de arranque predeterminado. \x0d\ En este punto, se ha establecido el nuevo kernel de Linux y la llamada al sistema recién agregada se ha convertido en parte del sistema operativo. Después de reiniciar Linux, el usuario puede usar la llamada al sistema en la aplicación. \x0d\\x0d\ (5) Utilice la nueva llamada al sistema\x0d\\x0d\ Utilice la nueva llamada al sistema mycall en la aplicación. También con fines experimentales, escribimos un ejemplo sencillo xtdy.c.
\x0d\\x0d\ /* xtdy.c */ \x0d\ #include \x0d\ _syscall1(int, mycall, int, ret) \x0d\ main() \x0d\ { \x0d\ printf("d \n ", mycall(100)); \x0d\ }\x0d\ Compila el programa: \x0d\ # cc -o xtdy xtdy.c\x0d\ Ejecuta: \x0d\ # xtdy\x0d\ Resultado: \x0d\ # 100 \x0d\ Tenga en cuenta que debido al uso de llamadas al sistema, el usuario debe ser el superusuario al compilar y ejecutar el programa.