Linux compila el kernel y agrega la llamada al sistema

  

Todos sabemos que la llamada a la función del sistema es la interfaz que el sistema operativo Unix /Linux brinda soporte para el programa del usuario. A través de estas aplicaciones de interfaz, el servicio se solicita al sistema operativo y el control se transfiere al sistema operativo. Una vez que se completa el servicio, el control y los resultados se devuelven al programa del usuario.

El objetivo principal de la llamada al sistema es permitir al usuario utilizar las funciones proporcionadas por el sistema operativo en lo que respecta a la administración de dispositivos, sistemas de entrada /salida, control de procesos y archivos, comunicación y administración de almacenamiento sin tener que conocer el programa del sistema. Estructura interna y detalles de hardware relacionados para reducir la carga del usuario y proteger el sistema y mejorar la utilización de los recursos.

Cuando se llama a la función del sistema, se transferirá del estado del usuario (también llamado estado) al estado nuclear (también llamado estado). Ayer, mi amigo de Xinan también me preguntó la diferencia entre mi administración y mi actitud. Creo que hay una gran diferencia aquí. En el estado de administración, todos los recursos del sistema se pueden usar para llamar a la función privilegiada del sistema. La actitud no es aceptable. Debe ejecutarse en un estado administrado cuando se ejecuta la llamada a la función del sistema.

Y si necesito agregar una llamada a la función del sistema a mi sistema Linux, tengo que averiguar cómo el sistema llama a esas funciones y cómo cambia de un estado a otro. En Linux, puede ingresar el estado de la tubería a través de interrupciones. Este tipo de interrupción se denomina interrupción de acceso.

Procedimientos para llamadas de sistema en el kernel

En sistemas Linux, las llamadas de sistema se implementan como un tipo de excepción que ejecuta las instrucciones de código de máquina adecuadas para generar una señal de excepción. Un efecto importante de generar una interrupción o excepción es que el sistema cambia automáticamente el estado del usuario al estado central para procesarlo.

Los programas en modo usuario solo pueden ejecutar funciones privilegiadas del kernel atrapándolas en el kernel del sistema (ejecutando instrucciones int). Una vez que se completa la llamada al sistema, el sistema ejecuta otro conjunto de instrucciones de función (instrucciones iret) para devolver el sistema al modo de usuario, y el control regresa al proceso.

La instrucción real que utiliza Linux para implementar excepciones de llamadas al sistema es:

int $ 0x80

Esta instrucción usa el número de vector de interrupción /excepción 128 (es decir, hexadecimal 80) Transferir el control al kernel (para cambio de modo).

Para lograr la programación sin utilizar las instrucciones de la máquina cuando se usan llamadas al sistema, se proporciona una breve subrutina para cada llamada al sistema en la biblioteca de lenguaje C estándar para completar la programación del código de la máquina.

De hecho, el segmento de código de máquina es muy corto. Todo lo que tiene que hacer es cargar los parámetros enviados a la llamada del sistema en los registros de la CPU y luego ejecutar la instrucción int $ 0x80. A continuación, ejecute la llamada al sistema.

El valor de retorno de la llamada del sistema se envía a un registro en la CPU. La subrutina de la biblioteca estándar toma este valor de retorno y lo envía de vuelta al programa del usuario.

Tomemos la llamada a la llamada al sistema getuid () como ejemplo:

Podemos ver que hay algunas definiciones de macros, podemos ver la definición de estas macros

(arch /i386 /kernel /entry.S).

… … …

#define SAVE_ALL \\

cld; \\

pushl % es; \\

pushl% ds; \\

pushl% eax; \\

pushl% ebp; \\

pushl% edi; \\

pushl% esi; \\

pushl% edx; \\

pushl% ecx; \\

pushl% ebx; \\

movl $ (__USER_DS),% edx; \\

movl% edx,% ds; \\

movl% edx,% es;

Podemos ver que SAVE_ALL es principalmente un registro de guardado Información, es decir, retención in situ. Entre ellos, movl $ (__ USER_DS),% edx; a partir de esta oración es rellenar el segmento DS, ES.

#define RESTORE_INT_REGS \\

popl% ebx; \\

popl% ecx; \\

popl% edx; \\

popl % esi; \\

popl% edi; \\

popl% ebp; \\

popl% eax

#define RESTORE_REGS \\

RESTORE_INT_REGS; \\

1: popl% ds; \\

2: popl% es; \\

.sección .fixup, " ax "; \\

3: movl $ 0, (% esp); \\

jmp 1b; \\

4: movl $ 0, (% esp); \\

jmp 2b; \\

.previous; \\

.section __ex_table, " a "; \\

.align 4; \\

.long 1b, 3b; \\

.long 2b, 4b; \\

.previous

ENTRY (ret_from_fork)

pushl% eax

call schedule_tail < Br>

GET_THREAD_INFO (% ebp)

popl% eax

jmp syscall_exit

Aquí finalizo principalmente la recuperación y el retorno en vivo.

ENTRY (system_call)

pushl% eax # save orig_eax

SAVE_ALL

GET_THREAD_INFO (% ebp)

# seguimiento de llamadas del sistema En operación

/* Nota, _TIF_SECCOMP es el número de bit 8, por lo que necesita testw y no testb * /

testw $ (_ TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP), TI_flags (% ebp)

jnz syscall_trace_entry

cmpl $ (nr_syscalls),% eax

jae syscall_badsys

syscall_call:

call * sys_call_table (,% eax, 4)

movl% eax, EAX (% esp) # almacena el valor de retorno

syscall_exit:

cli # asegúrese de No perdemos una interrupción

# 定 need_resched or sigpending

# entre el muestreo y el iret

movl TI_flags (% ebp),% ecx

testw $ _TIF_ALLWORK_MASK,% cx # current- > trabajar

JNE syscall_exit_work

restore_all:

movl EFLAGS (% esp),% eax # Mezclar EFLAGS, SS y CS

# Advertencia: OLDSS (% esp) contiene los valores incorrectos /aleatorios si

# estamos regresando al kernel.

# Vea los comentarios en process.c: Copy_thread () para detalles.

movb OLDSS (% esp),% ah

movb CS (% esp),% al

andl $ (VM_MASK |  (4 < < 8) |  3),% eax

cmpl $ ((4 < < 8) |  3),% eax

je ldt_ss # volviendo al espacio de usuario con LDT SS

restore_nocheck:

RESTORE_REGS

addl $ 4,% esp

1: iret

este párrafo se debe principalmente a completar la llamada. eax se coloca en el número de llamadas al sistema, porque eax probabilidades de ser utilizado, por lo que primero guardar su valor. llamada * sys_call_table (,% eax, 4) calculado que se llama una entrada.

en donde, el sys_call_table LINUX es una tabla de llamadas al sistema, lo que existe bajo el arco directorio /i386 /kernel /sys_call_table.S.

.data

ENTRADA (sys_call_table)

.long sys_restart_syscall /* 0 - antigua " Configuración () " llamada al sistema, que se utiliza para reiniciar * /

.long sys_exit

.long sys_fork

.long sys_read

.long sys_write

.long sys_open /* 5 * /

… …

… …

.long sys_mq_timedreceive /* 280 * /

.long sys_mq_notify

.long sys_mq_getsetattr

.long sys_ni_syscall /* reservado para kexec * /

.long sys_waitid

.long sys_ni_syscall /* 285 * //* disponible * /

Copyright © Conocimiento de Windows All Rights Reserved