Вы находитесь на странице: 1из 13

ESO/SOL. Tema 4.

Llamadas al Sistema
Juan Carlos Perez y Sergio Saez

ESO/SOL. Tema 4. Llamadas al Sistema

Table of Contents
Tema 4. Llamadas al Sistema............................................................................................................................1
4.1 Introduccin.......................................................................................................................................1
4.2 Estructura de un proceso en Linux.....................................................................................................1
4.3 Interfaz con el sistema operativo.......................................................................................................2
4.3.1 Interfaz ofrecida por el ncleo...........................................................................................2
4.3.2 Interfaz ofrecida al programador (API).............................................................................3
4.4 Ejemplo de invocacin.......................................................................................................................4
4.5 Biblioteca de llamadas al sistema......................................................................................................5
4.5.1 La biblioteca de llamadas glibc.........................................................................................6
4.5.2 Cdigo de retorno..............................................................................................................7
4.6 Entrando en el ncleo.........................................................................................................................7
4.6.1 Dentro de system_call........................................................................................................8
4.6.2 Recogida de parmetros.....................................................................................................9
4.7 Ejecucin de la llamada al sistema....................................................................................................9
4.8 Saliendo del ncleo: ret_from_syscall.............................................................................................10
4.9 Resumen...........................................................................................................................................10

Tema 4. Llamadas al Sistema


Juan Carlos Prez y Sergio Sez
Juan Carlos Prez (Ingls)
Sergio Sez

jcperez@disca.upv.es
ssaez@disca.upv.es

4.1 Introduccin
Estudio detallado del mecanismo mediante el cual Linux implementa las llamadas al sistema en una
arquitectura i386.
Un sistema operativo est definido por los servicios que ofrece en relacin con el acceso a
entrada/salida, procesos, manejo de memoria, envio de seales, tiempo, etc.
A los servicios del S.O. se accede a travs de las llamadas al sistema: open, read, fork,
mmap, kill, time, etc.
La llamada al sistema la invoca un proceso de usuario (o mejor dicho un proceso en modo usuario) y
es servida por el ncleo.
Una llamada al sistema implica pasar o saltar del cdigo del usuario al cdigo del ncleo. Este
salto conlleva un cambio en el modo del funcionamiento del procesador. El procesador debe pasar de
modo usuario (acceso restringido a los recursos) a modo supervisor o privilegiado (recordemos que
no tiene nada que ver con el superusario root).

4.2 Estructura de un proceso en Linux


Un proceso en Linux, aunque tiene un modelo de memoria plano, est estructurado en dos zonas de
memoria:
La zona del usuario, normalmente los tres primeros gigabytes de las direcciones lgicas.
La zona del ncleo, que ocupa el cuarto gigabyte.
La zona del ncleo de Linux est "mapeada" en todos los procesos del sistema.
Esta estructura coincide con los dos modos del procesador que utiliza Linux:
El cdigo de la zona del ncleo se ejecuta siempre en modo supervisor.
El cdigo presente en la zona del usuario se ejecuta en modo usuario.

Tema 4. Llamadas al Sistema

ESO/SOL. Tema 4. Llamadas al Sistema

4.3 Interfaz con el sistema operativo


Se pueden distinguir dos puntos de vista en la interfaz ofrecida por las llamadas al sistema:
1. La interfaz ofrecida por el ncleo del sistema operativo.
Es una interfaz definida a nivel de lenguaje ensamblador.
Depende directamente del "hardware" sobre el cual se est ejecutando el S.O.:
Registros del procesador, cmo se cambia de modo y se salta del cdigo de usuario
al cdigo del ncleo (jump, call, trap, int ...), etc.
2. La interfaz ofrecida al programador o usuario (API).
MSDOS
Documentada a nivel de ensamblador: Interrupcin a la que hay que llamar,
valores de los registros que hay que cargar y valores de retorno.
UNIX
Funciones estndar en lenguaje C.
P.ej. int kill (pid_t pid, int sig);

4.3.1 Interfaz ofrecida por el ncleo


El ncleo de Linux, en la arquitectura i386, utiliza la instruccin int 0x80 como puerta de entrada
en el ncleo. Recurdese que el manejador para la interrupcin software se instala en la funcin
trap_init()[arch/i386/kernel/traps.c#L916]. El nmero de la interrupcin software a utilizar esta definido
por la constante SYSCALL_VECTOR[include/asmi386/hw_irq.h#L19].
PARMETROS DE ENTRADA
Cdigo del servicio requerido en el registro eax. En el fichero
include/asmi386/unistd.h aparecen listadas todas las llamadas al sistema
que ofrece Linux con su correspondiente nmero. Contiene tambin la
implementacin de algunas llamadas al sistema de uso interno del propio Linux.
Si la llamada al sistema espera algn parmetro, Linux los pasa en los siguientes
registros del propio procesador.
%ebx
%ecx
%edx
%esi
%edi

arg
arg
arg
arg
arg

1
2
3
4
5

VALORES DE SALIDA
En el registro eax se devuelve el cdigo de retorno.

4.3 Interfaz con el sistema operativo

ESO/SOL. Tema 4. Llamadas al Sistema

4.3.2 Interfaz ofrecida al programador (API)


Todas las implementaciones de UNIX disponen de unas bibliotecas de usuario que esconden la
implementacin concreta de las llamadas al sistema (la interfaz real ofrecida por el S.O.) y ofrecen al
programador una interfaz C que presenta las siguientes ventajas:
Facilidad de uso al acceder desde un lenguaje de alto nivel.
Portabilidad entre arquitecturas: Linuxsparc, Linuxi386, etc.
Portabilidad entre diferentes versiones de UNIX: estndar POSIX. El estndar POSIX se
define slo a nivel de interfaz, no a nivel de implementacin real. De hecho, hasy sistemas
noUNIX, como Windows NT, que ofrecen una interfaz POSIX.
Todas las llamadas al sistema se encuentran documentadas en la seccin 2 del manual en lnea de
UNIX:
# man 2 kill
# man 2 kill
KILL(2)

Linux Programmer's Manual

KILL(2)

NAME
kill send signal to a process
SYNOPSIS
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
DESCRIPTION
The kill system call can be used to send any signal to any pro
cess group or process.
If pid is positive, then signal sig is sent to pid.
If pid equals 0, then sig is sent to every process in the process
group of the current process.
If pid equals 1, then sig is sent to every process except for
process 1 (init), but see below.
If pid is less than 1, then sig is sent to every process in
process group pid.

the

If sig is 0, then no signal is sent, but error checking is still


performed.
RETURN VALUE
On success, zero is returned.
errno is set appropriately.

On

error,

is

returned,

and

ERRORS
EINVAL An invalid signal was specified.
ESRCH

The pid or process group does not exist. Note that an


existing process might be a zombie, a process which
already committed termination, but has not yet been
wait()ed for.

EPERM

The process does not have permission to send the signal to


any of the receiving processes. For a process to have

4.3.2 Interfaz ofrecida al programador (API)

ESO/SOL. Tema 4. Llamadas al Sistema


permission to send a signal to process pid it must either
have root privileges, or the real or effective user ID of
the sending process must equal the real or saved setuser
ID of the receiving process. In the case of SIGCONT it
suffices when the sending and receiving processes belong
to the same session.
...

En adelante utilizaremos la llamada al sistema kill(2) como ejemplo.

4.4 Ejemplo de invocacin


Ejemplo de invocacin de la llamada al sistema int nice(int);
Detalle de los anillos de prioridad:
En la figura se observa la utilizacin de los anillos o niveles de prioridad de la arquitectura i386 por
parte del ncleo de Linux.

Detalle del mapa de memoria de un proceso:

4.4 Ejemplo de invocacin

ESO/SOL. Tema 4. Llamadas al Sistema

En la figura se muestra la utilizacin del espacio de direcciones por parte de un proceso de usuario.
El cdigo del usuario puede utilizar las direcciones lgicas desde 0 a 3GB y el ncleo desde 3GB a
4GB.

4.5 Biblioteca de llamadas al sistema


La biblioteca que contiene todas las llamadas al sistema es la libc.
Esta biblioteca se encarga de ocultar los detalles de la interfaz de las llamadas al sistema del ncleo
en forma de funciones en C. Dichas funciones trasladan los parmetros que reciben, normalmente a
traves de la pila, en los registros del procesador apropiados, invocan al S.O., recogen el cdigo de
retorno (asignndolo tpicamente a la variable errno), etc. En algunos casos concretos, las llamadas
al sistema que ofrece la biblioteca no se corresponden con las que ofrece el ncleo.
Existen casos en los que dos llamadas al sistema de la biblioteca coinciden con la misma llamada al
sistema "real" (P.Ej. waitpid y wait4 invocan ambas a la llamada al sistema wait4).
Incluso algunas supuestas llamadas al sistema ofrecidas por la biblioteca son implementadas
completamente por ella misma, con lo que el ncleo del S.O. no llega a invocarse.
Con estos mecanismos, la biblioteca es capaz de ofrecer una interfaz estndar, p. ej. POSIX, aunque
las llamadas al sistema que ofrece el ncleo del S.O. no coincidan exactamente con dicho estndar.
En esta asignatura nos centraremos nicamente en las llamadas al sistema "reales".
Inicialmente, en Linux, la libc la mantenan Linus Torvalds et al.. Actualmente, se utiliza la
biblioteca de GNU (glibc).
El cdigo de la biblioteca NO pertenece al ncleo del S.O., sino que est en el espacio de direcciones
del usuario. Por lo tanto, el cdigo de las bibliotecas se ejecuta todava en modo usuario.
4.5 Biblioteca de llamadas al sistema

ESO/SOL. Tema 4. Llamadas al Sistema

4.5.1 La biblioteca de llamadas glibc


Existen dos versiones de esta biblioteca con idntica funcionalidad:
La que se enlaza de forma esttica (libc.a), y est incluida en el propio programa
ejecutable del usuario.
La de enlace dinmico (libc.so) que se incorpora al proceso de usuario slo cuando es
necesario, y su cdigo es compartido por todos los procesos que la utilizan.
La biblioteca GNU C es realmente compleja pues los mismos fuentes se pueden compilar sobre
multitud de sistemas UNIX y sobre diferentes arquitecturas.
El cdigo de la llamada al sistema est declarado en una macro que se evala en tiempo de
compilacin, dependiendo su valor del S.O. y la arquitectura para la cual se estn compilando las
funciones. O sea, el cdigo en ensamblador que realiza la llamada al sistema no existe en un fichero
sino que se crea y compila a partir de unos ficheros de especificaciones del S.O. y la arquitectura de
destino.
El resultado de compilar los fuentes de la libc es son los ficheros libc.a y libc.so, versin
esttica y dinmica de la biblioteca respectivamente. Dentro de los ficheros de biblioteca estn
empaquetados, como si de un fichero arj o zip se tratara, los bloques de cdigo mquina de todas las
funciones.
La orden ar(1) se utiliza para trabajar con bibliotecas (crear, listar, aadir y borrar los ficheros que
contienen las funciones).
Con la siguiente orden podemos mostrar todos los ficheros contenidos en la biblioteca:
# ar t /usr/lib/libc.a
initfirst.o
libcstart.o
setinit.o
sysdep.o
version.o
check_fds.o
...

con la opcin x en lugar de t se puede extraer un fichero de la biblioteca. Para extraer el fichero
kill.o, que contiene la llamada al sistema kill(2) la orden sera:
# ar x /usr/lib/libc.a kill.o
Con la utilidad objdump(1) se puede desensamblar cualquier cdigo objeto o ejecutable. El
siguiente fragmento de cdigo representa la llamada al sistema kill.
# objdump d kill.o
kill.o:

file format elf32i386

Disassembly of section .text:


00000000 <__kill>:
0:
89 da
2:
8b 4c 24 08
6:
8b 5c 24 04

4.5.1 La biblioteca de llamadas glibc

mov
mov
mov

%ebx,%edx
0x8(%esp,1),%ecx
0x4(%esp,1),%ebx

ESO/SOL. Tema 4. Llamadas al Sistema


a:
f:
11:
13:
18:
1e:

b8
cd
89
3d
0f
c3

25 00 00 00
80
d3
01 f0 ff ff
83 fc ff ff ff

mov
int
mov
cmp
jae
ret

$0x25,%eax
$0x80
%edx,%ebx
$0xfffff001,%eax
1a <__kill+0x1a>

Con la utilidad strace(1) se puede ver cmo los programas hacen uso de las llamadas al sistema.
Acepta como parmetro el nombre de un ejecutable y lo ejecuta volcando en la salida estndar de
error todas las llamadas al sistema que ste realiza con sus respectivos parmetros.
# strace ls
execve("/bin/ls", ["ls"], %[/* 34 vars */]) = 0
uname({sys="Linux", node="viver", ...}) = 0
brk(0)
= 0x8053448
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
1, 0) = 0x40017000
...
open("/lib/i586/libc.so.6", O_RDONLY)
= 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\264\313"...,
1024) = 1024
...
open(".", O_RDONLY|O_NONBLOCK|0x10000) = 3
...
write(1, "11introduccion\t\t21arranque\t."..., 81) = 81
...
_exit(0)

4.5.2 Cdigo de retorno


En la arquitectrua i386, Linux devuelve el cdigo de retorno de la llamada al sistema en el registro
eax.
Cuando la llamada no ha tenido xito, el valor devuelto es negativo. Si es negativo, la biblioteca
copia dicho valor sobre una variable global llamada errno y devuelve 1 como valor de retorno de
la funcin Aun as, algunas llamadas realizadas con xito pueden devolver un valor negativo (p.ej.
lseek). Actualmente, el rango de errores que puede devolver una llamada al sistema se encuentra
entre 1 y 4095 (0xfffff001). La biblioteca debe ser capaz de determinar cundo el valor
devuelto es un error y tratarlo de forma adecuada. . La rutina syscall_error es la encargada de
hacerlo.
La variable errno contiene el cdigo de error de la ltima llamada que fall. Una llamada que se
realice con xito no modifica errno. Ms informacin con:
# man 3 errno.
La variable errno est declarada en la propia biblioteca.

4.6 Entrando en el ncleo


La int 0x80 produce un salto a la zona de cdigo del sistema operativo. Concretamente se salta a
la funcin system_call[arch/i386/kernel/entry.S#L187]. La interrupcin 0x80 se asocia con la funcin
system_call al inicializar Linux en la lnea arch/i386/kernel/traps.c#L943 de la
funcin trap_init() invocada desde la funcin start_kernel[init/main.c#L545].
En el proceso de salto ...
4.5.2 Cdigo de retorno

ESO/SOL. Tema 4. Llamadas al Sistema


El procesador pasa de modo usuario ("ring level" 3 en la arquitectura i386) a modo
supervisor ("ring level" 0).
Se cambia el puntero de
pila para que apunte a la
pila del ncleo del
proceso y se guardan en
dicha pila algunso
registros (SS, ESP,
EFLAGS, CS, EIP). En la
arquitectura i386 cada
nivel de privilegio tiene
un puntero de pila
distinto por motivos de
seguridad.
Evidentemente la instruccin int necesita muchos ciclos de reloj para completarse.

4.6.1 Dentro de system_call


1. Primero guarda el cdigo de la llamada al sistema en la pila del ncleo
(#195[arch/i386/kernel/entry.S#L195]).
2. Lo primero es guardar todos los registros del procesador con la macro
SAVE_ALL[arch/i386/kernel/entry.S#L85] (#196[arch/i386/kernel/entry.S#L196]).
3. Se pone el puntero al PCB de la tarea actual en el registro ebx (#197[arch/i386/kernel/entry.S#L197]).
4. Se verifica si el proceso padre est monitorizando este proceso (#198[arch/i386/kernel/entry.S#L198]), en
cuyo caso se le informa de que su hijo est realizando una llamada al sistema, antes y despus de
servirla (#232[arch/i386/kernel/entry.S#L232]).
5. Se comprueba que el nmero de llamada pedido es vlido (o si la llamada no est implementada). Si
no es vlido se retorna inmediatamente con el cdigo de error ENOSYS
(#243[arch/i386/kernel/entry.S#L243]).
6. ...

6. Se llama a la funcin que sirve la llamada pedida:


202 call *SYMBOL_NAME(sys_call_table)(,%eax,4)
sys_call_table[arch/i386/kernel/entry.S#L397] es un vector de direcciones de salto que contiene las
direcciones de la funciones que sirven cada una de las llamadas al sistema. Cada direccin ocupa
4 bytes.
7. Finalmente se pone en el registro eax el cdigo de retorno, y se ejecuta la rutina
ret_from_sys_call[arch/i386/kernel/entry.S#L204].
Realmente se almacena el valor del registro eax en la posicin que ocupa dicho registro en la pila
del ncleo (EAX[arch/i386/kernel/entry.S#L55](%esp)). Cuando se saquen todos los registros de
la pila con la macro RESTORE_ALL[arch/i386/kernel/entry.S#L100], el registro se establecer al valor de
retorno, que es lo que espera la biblioteca libc.

4.6.1 Dentro de system_call

ESO/SOL. Tema 4. Llamadas al Sistema

4.6.2 Recogida de parmetros


En C normalmente se utiliza la pila para pasar parmetros entre funciones. Antes de realizar la
llamada a una funcin se insertan en la pila todos los parmetros luego se invoca a la funcin y sta
lee los parmetros de la pila.

Estructura de la pila en el i386 al llamar a una funcin.


En nuestro caso, la macro SAVE_ALL[arch/i386/kernel/entry.S#L85] guarda los registros (que es donde se
reciben los parmetros de las llamadas) en la pila (push), por lo que si luego llamamos a una
funcin C, sta se comportar como si otra funcin en C le hubiera pasado los parmetros.
El orden en el que se insertan en la pila es importante. Los ltimos en insertarse en la pila son
los primeros parmetros en la declaracin de la funcin en C.

4.7 Ejecucin de la llamada al sistema


Siguiendo con el ejemplo de la llamada kill, cuando se ejecute la instruccin
202 call *SYMBOL_NAME(sys_call_table)(,%eax,4)
se llamar a la funcin C cuya direccin se encuentra en la entrada
37 (include/asmi386/unistd.h#L44) de la tabla
sys_call_table[arch/i386/kernel/entry.S#L436]. Recordemos que en el cdigo de la biblioteca libc se
asigno el valor 0x25(37) al registro eax antes de ejecutar la instruccin int 0x80:
...
a:
f:

b8 25 00 00 00
cd 80

4.6.2 Recogida de parmetros

mov
int

$0x25,%eax
$0x80

ESO/SOL. Tema 4. Llamadas al Sistema


...

y que el tamao de cada direccin es de 32 bits, o sea 4 bytes.


La funcin invocada es sys_kill(int pid, int sig)[kernel/signal.c#L978], que se encargar de
enviar la seal sig al proceso con pid pid.
Los parmetros que el usuario le paso a la funcin kill de la biblioteca libc han pasado por los
registros %ebx y %ecx, luego se han copiado en la pila del ncleo y ese valor de la pila, en el
lenguaje C, se ve ahora como los parmetro pid y sig de la funcin sys_kill.

4.8 Saliendo del ncleo: ret_from_syscall


Al finalizar la ejecucin de la llamada al sistema se ejecuta el cdigo que se encuentra en
ret_from_sys_call[arch/i386/kernel/entry.S#L204]. Este cdigo lleva a cabo algunas comprobaciones antes de
volver a modo usuario.
Durante la ejecucin de la llamada al sistema el proceso ha podido cambiar de estado, y por lo tanto,
haberse marcado la necesidad de planificar de nuevo, poniendo la variable need_resched a cierto.
Aqu se comprueba si esta variable est a cierto y en caso afirmativo llamamos al
planificador[kernel/sched.c#L539] (#L206[arch/i386/kernel/entry.S#L206]).
Se comprueba si el proceso activo tiene seales pendientes, en cuyo caso se le envan
(#L208[arch/i386/kernel/entry.S#L208]).
Finalmente se restauran todos los registros (incluido el %eax que contiene el cdigo de retorno) y se
retorna de la interrupcin (int), reponiendo el modo del procesador y la pila a la que tiene acceso el
proceso en modo usuario. Se puede observar que la ejecucin ms frecuente de
system_call[arch/i386/kernel/entry.S#L187] (la llamada es correcta, no est siendo monitorizada, no hay
que replanificar y no hay seales pendientes) est optimizada para no tomar absolutamente ningn
salto, a excepcin de la propia llamada a la funcin.
Los procesadores actuales basan la mayor parte de sus prestaciones en la ejecucin segmentada de
instrucciones, y las instrucciones de salto suelen forzar el vaciado de la unidad de ejecucin si el
destino de los mimos no se predice correctamente. El cdigo de Linux intenta minimizar el nmero
de saltos dentro del flujo de control ms frecuente.

4.9 Resumen
1. La biblioteca mete en los registros del procesador los parmetros de la llamada.
2. Se produce la interrupcin software (trap) 0x80. El descriptor de interrupcin. 0x80 apunta a la
rutina system_call.
3. Se guardan el registro %eax. El resto de los registros con SAVE_ALL.
4. Se verifica que el nmero de llamada al sistema corresponde con una llamada vlida.
5. Se salta a la funcin que implementa el servicio pedido:
call *SYMBOL_NAME(sys_call_table)(,%eax,4)

6. Si mientras se atenda la llamada al sistema se ha producido algn evento que requiera llamar al
planificador, se llama en este punto.
7. Si el proceso al que se va a retornar tiene seales pendientes, se le envan ahora.
8. Se restauran los valores de los registros con RESTORE_ALL y se vuelve de la interrupcin software.
4.8 Saliendo del ncleo: ret_from_syscall

10

ESO/SOL. Tema 4. Llamadas al Sistema


9. La biblioteca comprueba si la llamada ha producido algn error, y en este caso guarda en la variable
errno el valor de retorno.

4.8 Saliendo del ncleo: ret_from_syscall

11

Вам также может понравиться