Cómo agregar una llamada al sistema al kernel de Linux
1. Agregar llamadas al sistema en Linux0.11:
Agregué una nueva llamada al sistema al kernel Linux0.11 en bochs2.2.1. Los pasos son los siguientes:
1. Agregue: #define __NR_mytest 87 a/usr/src/linux/include/unistd.h
Luego declare el prototipo de función a continuación: int mytest(); > 2. Agregue: extern int sys_mytest() a /usr/src/linux/include/linux/sys.h;
Luego agregue sys_mytest al final de sys_call_table
3. Agregue la implementación de la función en /usr/src/linux/kernel/sys.c de la siguiente manera:
int sys_mytest(){
printk("¡Esto es una prueba!") ;
return 123;
}
4. Agregue 1 al número de llamada del sistema en /usr/src/linux/kernel/system_call.s (originalmente 86 Cambiado a 87)
5. Luego vaya al directorio /usr/src/linux para compilar el kernel make clean
6. /include/ unistd.h /usr/include/unistd.h
7. restablecer bochs
8 Genere el archivo test.c en /usr/root de la siguiente manera:
p>
#define __LIBRARY__
#include lt;unistd.hgt;
_syscall0(int, mytest)
int main(){ p>
int a;
a = miprueba();
printf("d", a); >
}
9. Luego ejecute a.out después de compilar gcc test.c. Se pasaron todos los pasos anteriores, pero cada llamada devuelve -1. la operación no está permitida), no sé por qué.
Expertos que conozcan el sistema me pueden decir, ¡se lo agradecería mucho! ¡Este problema me ha preocupado durante mucho tiempo!
2. Agregar llamadas al sistema al nuevo kernel de Linux
Cómo agregar nuevas llamadas al sistema en el sistema Linux
Las llamadas al sistema son entre la aplicación y el sistema operativo. Interfaz funcional del núcleo del sistema. 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.
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 también sus aplicaciones comerciales 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?
1 mecanismo de llamada al sistema Linux
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:
Int $0x80
Esta instrucción utiliza el vector de interrupción/excepción número 128 (es decir, 80 en hexadecimal) para transferir el control transferido a el núcleo. 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.
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.
Estas instrucciones macro tienen un formato de nombre similar al siguiente:
_syscallN (parámetros)
donde N es el número de parámetros necesarios para la llamada al sistema, y los parámetros son un conjunto de parámetros. 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(), se usaría:
_syscall1(int, setuid, uid_t, uid)
El primer parámetro de syscallN () macro int indica que 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.
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().
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.
2 Agregar una nueva llamada al sistema
Si el usuario agrega una nueva llamada al sistema en Linux, debe seguir varios pasos para agregarla exitosamente. Los siguientes pasos explican en detalle cómo agregarla. una llamada al sistema.
(1) Agregar código fuente
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. El nombre debe ser 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:
asmlinkage int sys_mycall(int número)
{
return number
}
Como ejemplo más simple, nuestra nueva llamada al sistema solo devuelve un valor de tipo entero. .
(2) Conectar la nueva llamada al sistema
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.
En la versión del kernel de Linux que estamos usando (RedHat 6.0, kernel 2.2.5-15), el primer archivo a modificar es:
/usr/src/linux /include /asm-i386/unistd.h
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 del archivo es el siguiente:
#define __NR_name NNN
Entre ellos, el nombre se reemplaza por el nombre de la llamada del sistema y NNN es el número correspondiente al llamada al 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:
#define __NR_mycall 191
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 de Linux -2.2 kernel en sí se ha utilizado 190.
El segundo archivo a modificar es:
/usr/src/linux/arch/i386/kernel/entry.S
Este archivo contiene una lista similar a lo siguiente:
.long SYMBOL_NAME()
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:
.long SYMBOL_NAME(sys_mycall)
(3) Reconstruir el nuevo kernel de Linux
Para hacer La nueva llamada al sistema entra en vigor. Es necesario reconstruir el kernel de Linux. Esto requiere iniciar sesión como superusuario.
#pwd
/usr/src/linux
#
El superusuario está en el directorio de trabajo actual (/usr/ src/linux ), el kernel se puede reconstruir.
#make config
#make dep
#make clearn
#make bzImage
Después de la compilación completado, el sistema genera un archivo de imagen del kernel comprimido que se puede usar para la instalación:
/usr/src/linux/arch/i386/boot/bzImage
(4) Usar nuevo Sistema de arranque del kernel
Para utilizar las nuevas llamadas al sistema, es necesario reiniciar el sistema con un nuevo kernel reconstruido.
Para hacer esto, necesita modificar el archivo /etc/lilo.conf. En nuestro sistema, el contenido del archivo es el siguiente:
boot=/dev/hda
. map=/boot/map
install=/boot/boot.b
mensaje
timeout=50
image=/boot /vmlinuz-2.2.5 -15
label=linux
root=/dev/hdb1
solo lectura
other= /dev/hda1
p>
label=dos
table=/dev/had
Primero edite el archivo y agregue un nuevo kernel de arranque:
image=/boot /bzImage-new
label=linux-new
root=/dev/hdb1
solo lectura
La adición está completa. El contenido del archivo es el siguiente:
boot=/dev/hda
map=/boot/map
<. p>install=/boot/boot.bmensaje
timeout=50
image=/boot/bzImage-new
label=linux-new
root =/dev/hdb1
solo lectura
image=/boot/vmlinuz-2.2.5-15
label=linux
root=/dev/hdb1
solo lectura
other=/dev/hda1
label=dos
table=/ dev/hda
De esta manera, la nueva 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:
#cp /usr/src/linux/arch/i386/boot/zImage /boot/bzImage-new
En segundo lugar configura lilo:
# /sbin/lilo
Ahora, al reiniciar el sistema, hay tres opciones después del arranque: indicador: linux-new, Linux, Dos, el nuevo kernel se convierte en el kernel de arranque predeterminado.
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.
(5) Utilice la nueva llamada al sistema
Utilice la llamada al sistema mycall recién agregada en la aplicación. También con fines experimentales, escribimos un ejemplo sencillo xtdy.c.
/* xtdy.c */
#include
_syscall1(int, mycall, int, ret)
main()
{
printf("d \n", mycall(100));
}
Compila el programa: p>
p>
# cc -o xtdy xtdy.c
Ejecución:
# xtdy
Resultado:
# 100
Tenga en cuenta que debido al uso de llamadas al sistema, el usuario debe ser el superusuario al compilar y ejecutar el programa.