Existen dos mecanismos bajo Linux para implementar las llamadas al sistema:
- las llamadas puerta lcall7/lcall27 ;
- interrupción software int 0x80.
Los programas nativos de Linux utilizan int 0x80 mientras que los binarios de los distintos tipos de UNIX (Solaris, UnixWare 7 etc.) usan el mecanismo lcall7. El nombre 'lcall7' es históricamente engañoso porque también cubre lcall27 (ej. Solaris/x86), pero la función manejadora es llamada lcall7_func.
Cuando el sistema arranca, la función
arch/i386/kernel/traps.c:trap_init() es llamada, la cual inicializa el IDT, por lo tanto el vector 0x80 (del tipo 15, dpl 3) apunta a la dirección de la entrada system_call desde
arch/i386/kernel/entry.S.
Cuando una aplicación del espacio de usuario realiza una llamada del sistema, los argumentos son pasados a través de los registros y la aplicación ejecuta la instrucción 'int 0x80'. Esto causa un reajuste en el modo núcleo y el procesador salta al punto de entrada system_call en
entry.S. Lo que esto hace es:
- Guarda los registros.
- Establece %ds y %es a KERNEL_DS, por lo tanto todas las referencias de datos (y segmentos extras) son hechas en el espacio de direcciones del núcleo.
- Si el valor de %eax es mayor que NR_syscalls (actualmente 256) fallará con el error ENOSYS.
- Si la tarea está siendo ptraced (tsk->ptrace & PF_TRACESYS), realiza un procesamiento especial. Esto es para soportar programas como strace (análogo a SVR4 truss(1)) o depuradores.
- Llamada sys_call_table+4*(syscall_number desde %eax). Esta tabla es inicializada en el mismo archivo (arch/i386/kernel/entry.S) para apuntar a los manejadores individuales de las llamadas al sistema, los cuales bajo Linux son (usualmente) prefijados con sys_, ej. sys_open, sys_exit, etc. Estos manejadores de las llamadas al sistema de C encontrarán sus argumentos en la pila donde SAVE_ALL las almacenó.
- Entra en el 'camino de retorno de la llamada al sistema'. Esta es una etiqueta separada porque es usada no sólo por int 0x80 sino también por lcall7, lcall27. Esto es, relacionado con el manejo de tasklets (incluyendo bottom halves), chequeando si un schedule() es necesitado (tsk->need_resched !=0), chequeando si hay señales pendientes y por lo tanto manejándolas.
Linux soporta hasta 6 argumentos para las llamadas al sistema. Ellas son pasadas en %ebx, %ecx, %edx, %esi, %edi (y %ebp usado temporalmente, ver
_syscall6() en
asm-i386/unistd.h). El número de llamadas al sistema es pasado a través de %eax.