martes, 20 de mayo de 2014

Debugging (I) Llamadas al sistema (System calls)

Las llamadas al sistema, aunque parecen funciones, son un mecanismo más complejo que una simple bifurcación con retorno y a lo largo de esta serie de artículos entenderemos, con ejemplos prácticos, como funcionan.

Los lenguajes de programación y casi toda la documentación asociada a ellos apenas hacen distinción de ello pero bajo el concepto general de función se esconden dos cosas bien diferentes.


  • La función "normal" entendida como un salto a otra zona del programa y retorno a la instrucción siguiente al salto.
  • La llamada al sistema  tiene algo más de complejidad como veremos más adelante pero antes explicaremos la necesidad de la existencia de este tipo de funciones.


Se puede definir una llamada al sistema como una función que se ejecuta dentro del espacio del kernel. Ahora vamos a ver como está montada en la arquitectura x86 la protección de memoria. (Expongo este modelo por ser el más conocido, pero sea cual sea la arquitectura existe un modelo por el que se estructura la seguridad en la memoria, puede tener más a menos niveles, ser visto como anillo o como capa, etc. pero siempre hay una distinción entre memoria/acceso privilegiado y memoria/acceso de usuario)

En la imagen siguiente se puede ver como está estructurada en anillos con cuatro capas siendo la más interna (y mas privilegiada) el kernel en el centro del anillo.




En la mas externa, la que tiene menos privilegio, estarían los programas de usuario. Normalmente se conoce a esta capa como modo usuario (user mode).

No parece normal que un programa en modo usuario tenga que entrar a hacer "cosas del kernel", pero las cosas no son tan evidentes.

Supongamos una acción tan común como es abrir un fichero. Leamos un poco en detalle que hace la función open().

Esta función nos devuelve un file descriptor que no es más que un número de orden en una tabla que contiene los ficheros abiertos por el proceso. Estas tablas, a su vez, apunta a otras tablas y asi.... hasta el hardware.


En algún momento seguro que necesitaremos modificar algo que está en memoria privilegiada.
La solución a este problema evidentemente no debe pasar por que el programa tenga acceso a ese tipo de memoria pues expondríamos al kernel y a sus críticas estructuras de datos a todo tipo de errores. Una consecuencia inmediata de ello es que un pequeño error en un programa de usuario podría hacer que el kernel finalizará de manera anormal y todo el sistema se vendrá abajo.

Para dar solución a este problema se crearon las llamadas al sistema que permiten a los usuarios realizar una serie de acciones que necesitan ser realizas en modo kernel sin necesidad de tener ese nivel de privilegio.

Las llamadas al sistema no se realizan como las llamadas a funciones normales mediante un salto al código de la función si no que requiere un mecanismo que conmute del modo usuario al modo privilegiada. Dependiendo de la arquitectura existes varios sistemas aunque el más usado es generar una interrupción y todas las consecuencias que lleva consigo una interrupción de programa.

En la siguiente entrega veremos mediante un ejemplo práctico como se implementan las llamadas al sistema.


1 comentario: