|
|
Respuestas a preguntas frecuentes
|
|
| Qué hay acerca de la serie de parches ac (Alan Cox) ? |
|
- Cuál es la diferencia con los kernel de Linus?
Los kernel de Alan pueden parecer una prueba de cama para los kernel de
Linus. Mientras Linus es muy conservativo y solo aplica parches obios y
bien probados al kernel 2.4, Alan mantiene una serie de parches para el
kernel que contienen nuevos conceptos, más y/o nuevos drivers, y
parches más intrusivos. Si los parches demuestran ser estables, Alan
los presenta a Linus para incluirlos en el kernel oficial. (Notese que
actualmente el árbol -ac esta esencialmente en el limbo, conteniendo
parches que necesitan ser adelantados por Marcelo para el 2.4. No hay
árbol -ac para el 2.5)
Solo la serie -ac contiene todas las
correciones propuestas en la lista(s) de correo del kernel.
Con el estado actual del árbol de Linus, se
recomienda el uso de la series -ac.
- Dónde los consigo ?
Ve a ftp://ftp.kernel.org/pub/linux/kernel/people/alan/
donde "xx" es tu código de pais , e.j. "uk"
- Cómo los aplico ?
Ejemplo de como parchar del 2.4.2 -> 2.4.2-ac20. (Asumiendo que
linux-2.4.2.tar.bz2 y patch-2.4.2-ac20.bz2 ambos han sido descargados
del mismo directorio.
bzip2 -dc linux.2.4.2.tar.bz2 | tar xvf -
cd linux
bzip2 -dc ../patch-2.4.2-ac20.bz2 | patch -p1
- He descargado los archivos .gz en vez de los
.bz2
Mismo proceso, solo que se usa diferente programa para descomprimir.
gzip -dc linux.2.4.2.tar.gz | tar xvf -
cd linux
gzip -dc ../patch-2.4.2-ac20.gz | patch -p1
- Pero ya he aplicado un parche ac !
Entonces reversalo
:
bzip2 -dc patch-2.4.2-ac19.bz2 | patch -p1
-R
bzip2 -dc patch-2.4.2-ac20.bz2 | patch -p1
- Por qué no puede haber "diferencias
incrementales" entre las correcciones ac ?
Si estas interesado, estan en http://www.bzimage.org/
o ftp://sunsite.icm.edu.pl/pub/Linux/kernel/incr/2.4
|
|
|
|
Qué es una etiqueta asmlinkage ? |
|
|
La etiqueta asmlinkage es otra cosa que debemos
observar acerca de esta simple función. Es como un #define para algunos
gcc magic la cual le dice al compilador que la función no debe esperar
encontrar alguno de estos argumentos en los registros (una optimización
común), pero solo en la pila (stack) (stack) de la CPU. Rellama a nuestra previa
asercion que system_call consume, este es el primer argumento, el
número de llamada de sistema, y permite hasta cuatro argumentos más,
que son pasados a lo largo de la verdadera llamada de sistema. system_call
archiva este proceso simplemente dejando estos otros argumentos (los
cuales fueron pasados a este como registros) en la pila (stack). Todas las
llamadas de sistema son marcadas con la etiqueta asmlinkage, por eso
todas ellas buscan argumentos en la pila (stack). Por supuesto, en el caso de
las sys_ni_syscall, no son la excepción por que sys_ni_syscall no toma
ningun argumento , pero es un número para la mayoría de otras llamadas
del sistema. Y por eso veras etiquetas asmlinkage en frente de muchas
otras funciones.
|
|
|
|
|
-
|
Cómo
comienzo ? |
|
|
Una pregunta común hecha por un novato es "He
descomprimido este enorme tarball, y quiero usarlo, pero no se donde
comenzar!"
Puede parecer intimidatorio para ser confrontado
con una gran cantidad de código fuente, pero ten en cuenta, que hay
pocos hackers del kernel que entienden cada área del árbol del kernel.
Las personas se especializan. Si estas interesado
en TCP/IP, no necesitaras leer sobre código de sistema de archivos.
Piensa en que es lo quieres profundizar, y enfocate hacia ello.
Linux es un kernel de calidad profesional. Esto
hace dificil que este parezca un "proyecto de estudiante" con el cual
puedes aprender: las caracteristicas usuales ya estan implentadas, y
aun nivel en el cual se requiere un buen nivel de entendimiento antes
que puedar hacer hacking en el. Sin embargo, hay muchas cosas practicas
y utiles que puedes hacer hasta que hayas aprendido lo suficiente para verdaderamente
Comenzar en el hacking :
- Pruebas y anotaciones
- El nuevo código esta en constante evolución,
pruebalo. Seguramente te daras cuenta que hay algunos comportamientos
extraños: Aqui esta tu impetu para entender the donde
proviene ese comportamiento. Perfila cosas y sigueles el rastro (ej.
LTT), mira si puedes trabajar en lo que probablemente esta causando
problemas. Aprenderas de ese código por accidente. Consigue los parches
propuestos en las listas de correo del linux kernel y arboles como
los -mjc. Consigue y entiende que hace un parche en particular, y como
lo hace.
- Documentación
- Suena aburrido ? Talvez, le estes haciendo un
favor a todos, no seria solo para ti. Esfuerzate para explicar las
cosas de forma logica para tu entendimiento. La documentacion sobre los
comportamientos del linux kernel, requiere que entiendas el código. Lo encontraras facil
de leer si estas concentrado en responder una pregunta especifica.
Escribe articulos para kernelnewbies y hazlos revisar en el canal IRC.
Identifica irregularidades en las paginas-man (manual), y corrigelas.
Añade los documentos a las fuentes del kernel.
- Kernel janitors
- Kernel janitors es un proyecto para corregir
las APIs del kernel, en desuso, como mutación de código. Este es un
interesante proyecto. Una charla educativa sobre el, puede leerse aquí aquí.
|
|
|
|
|
|
Cómo
compilo un kernel ? |
|
|
(Estas instrucciones suponen que estamos
instalando la versión 2.4.0 del kernel, reemplaza todas las instancias,
con la versión de kernel que vas a compilar. Estas instrucciones son
también especificamente x86; la construcción para otras arquitecturas
puede diferir.
- Descarga el tarball de ftp.XX.kernel.org donde
XX es el código de tu pais. si no hay algún mirror para tu pais, escoge
el más cercano.
- Descomprime el tarball en tu directorio
/usr/src
bzip2 -dc linux-2.4.0.tar.bz2 | tar xvf -
(Reemplaza bzip2 por gzip si has descargado el .gz)
- Cambiate al directorio linux. Ahora necesitas
configurar el kernel para seleccionar las caracteristicas que
quieres/necesitas. Hay varias formas de hacerlo..
a. make config
preguntas tipo línea de comando.
b. make oldconfig
(Útil solo si mantienes el .config de una
compilación previa de otro kernel)
c. make menuconfig
(configuración basada en ncurses)
d. make gconfig
(configuración gráfica GTK basada en X-Windows)
e. make xconfig
(configuración gráfica QT basada en X-Windows)
- Ahora podemos compilar el kernel, pero primero
debemos compilar las dependencias.
make dep make bzImage
- Espera!, cuando esto haya finalizado, compila
alguna parte que talvez hayas seleccionado para ser modular.
make modules
-
Para la actual serie estable del linux kernel 2.6.x estos son los pasos
make
make modules
notese que ya no es necesario hacer 'make dep' en los kernels 2.6.x
- Cambia de usuario normal a root para poder
instalar el kernel y los modulos. Todo antes de este punto puede y debe
ser realizado como usuario normal, no hay necesidad de ser root para
compilar el kernel. Actualmente es una muy mala idea hacer todo como
root porque el root es demasiado poderoso, un simple error es capaz de
arruinar tu sistema por completo.
- Instala los modulos.
make modules_install
- Instala el nuevo kernel..
cp arch/i386/boot/bzImage /boot/vmlinuz-2.4.0 cp System.map /boot/System.map-2.4.0
- Edita /etc/lilo.conf, y añade
estas lineas...
image = /boot/vmlinuz-2.4.0 label = 2.4.0
También copia aquí la línea root=/dev/???.
- Ejecuta /sbin/lilo, reinicia, y disfruta. si
tienes problemas con modversions (simbolos terminados en _Rxxxxxxxx),
echa un vistazo a esta pregunta
en las preguntas frecuentes de la lista de correo del linux kernel,
para resolver el problema.
Aún no lo resuelves? Lee un tutorial más
profundo
En SPARC, debes seguir los siguientes pasos
-
NOTA: para soporte a 64 bits se recomienda usar versiones >
3.1 del compilador gcc
-
Descomprime el tarball que has descargado de kernel.org
tar xjvf linux-2.4.xx.tar.bz2
o si descargaste el tarball comprimido con gzip, es lo mismo solo que haces esto
tar xzvf linux-2.4.xx.tar.gz
-
Sigues la misma parte de configuración que en x86
-
Despues que hayas configurado las opciones de tu kernel, construye la imagen de
arranque haz:
make vmlinux
-
Ahora si construye e instala los modulos, tal y como se hace en x86:
make modules
A continuación:
make modules_install
-
Instala el nuevo kernel
cp vmlinux /boot/nuevo-kernel
A continuación instala System.map
cp System.map /boot/System.map-nuevo-kernel
- opcional, pero recomendado, comprimir la imagen de arranque, si tienes una
máquina un poco ya antigua, ej sun ultra enterprise 2, puede que tengas
problemas para arrancar si no comprimes la imagen, en las maquinas Sun modernas
es posible que no haya necesidad de hacerlo
gzip /boot/nuevo-kernel
-
Edita el archivo /etc/silo.conf y agrega las siguientes lineas
image=/boot/kernel.gz
label=nuevokernel
root=/dev/xxx
- no olvides cambiar la linea root=/dev/xxx??, ejemplo root=/dev/sda5
- no necesitas ejecutar /sbin/silo ya que el archivo de configuración se
analiza al arranque, pero si quieres asegurarte de que no hay errores en el
archivo /etc/silo.conf haz:
/sbin/silo
entonces te debe aparecer algo como esto:
/etc/silo.conf seems to be correct
eso significa que archivo de configuración parece tener correcta
la sintaxis, he aquí un archivo de configuración ejemplo de /etc/silo.conf
timeout=50
partition=5
root=/dev/sda5
read-only
image=/boot/vmlinux
label=linux
image=/boot/vmlinux.viejo
label=viejo
-
Reinicia y listo!
-
Para mayor información visita ultralinux.org
|
|
|
|
|
|
|
Quienes son ... los maestros ? |
|
|
|
Linus Torvalds.
Por favor, sea serio...
Alan Cox.
Alan nos visita de vez en cuando.
|
|
|
|
|
|
|
Cómo
aplico un parche ? |
|
|
La respuesta, depende de como fue creado el parche
especificamente desde que directorio fue aplicado. De forma general,
los parches son creados desde la raiz del árbol (/usr/src/linux),
y las siguientes instrucciones así lo suponen.
Por ejemplo consideremos que, has desempaquetado
un tarball de Linux 2.4.0, y quieres aplicar un parche de Linus patch-2.4.1.bz2,
el cual esta ubicado en /usr/src. Haz lo siguiente :
cd /usr/src/linux bzip2 -dc /usr/src/patch-2.4.1.bz2 | patch -p1 --dry-run
Usamos la opcion --dry-run para VERIFICAR que el parche se
aplicara correctamente. Esto puede ser un salvadidas a veces puede ser
un verdadero dolor de cabeza volver a un parche parcialmente aplicado.
La opcion -p1 nos muestra parte de las diferencias en los
nombres de las rutas para cada archivo reemplazado (mira la página
manualpatch(1) para más detalles). Ahora que has verificado
que se aplicara correctamente, ejecuta :
bzip2 -dc /usr/src/patch-2.4.1.bz2 | patch -p1
para aplicarlo. Y listo !. Luego de esto se procede a compilar el
kernel para poder usar las caracteristicas que brinde el parche
Esto es actualmente con los parches estandar simples de Linus, o
también puedes usar el script linux/scripts/patch-kernel para
que automaticamente aplique los parches por ti.
La situación con los otros parches no siempre es
tan simple. Por ejemplo, los pre parches de Linus (se encuentran en pub/linux/kernel/testing)
no son incrementales. Por eso es que pre10.bz2 debe ser
aplicado en encima del tarball del previo lanzamiento completo del
kernel. Ej, patch-2.4.8-pre2 va encima de un tarball 2.4.7
desempaquetado, *NO* encima de un kernel parchado 2.4.8-pre1. Si tienes
un kernel 2.4.8-pre1, puedes volverlo a 2.4.7 a través de la siguiente
sección (abajo) 'Reversando un parche'.
Los parches ac de Alan Cox (pub/linux/kernel/people/alan/)
siguen el mismo metodo, a menos de que consigas los parches
incrementales en bzimage.org.
Ocasionalmente querras probar un parche de la
lista de correo del linux kernel o similares. Generalmente van a
ser incrementales, opuestos a dicha versión (entonces, digamos que, 2.4.0-test1-ac22-hosedmm.diff
debería ser aplicado opuesto a 2.4.0-test1-ac22), y relativo al root.
Puedes necesitar jugar con la opcion -p.
A continuacion mostraremos un ejemplo de como
aplicar un parche alan cox, bueno supongamos que patch-2.4.22-rc.bz2
y patch-2.4.22-rc2-ac1.bz2 han sido descargados del mismo
sitio, a /usr/src/ entonces :
1. cd /usr/src/linux
2. Verificamos que el primer parche se aplicaria correctamente
bzip2 -dc ../patch-2.4.22-rc2.bz2 | patch -p1
--dry-run
Si el parche se aplicaria correctamente se veria algo como esto:
patching file arch/alpha/kernel/entry.S
patching file arch/alpha/kernel/process.c
patching file arch/alpha/kernel/smp.c
patching file arch/alpha/kernel/srmcons.c
patching file arch/alpha/mm/fault.c
patching file arch/arm/config.in
patching file arch/arm/mm/fault-common.c
patching file arch/cris/drivers/serial.c
patching file arch/i386/boot/setup.S
patching file arch/i386/config.in
patching file arch/i386/defconfig
patching file arch/i386/kernel/dmi_scan.c
y así sucesivamente ....
ahora
que sabemos que el parche se aplicara adecuadamente, entonces pasamos a
ejecutar la anterior línea de comando sin el parametro --dry-run
siguiente paso, una vez que se haya aplicado exitosamente el patch-2.4.22-rc2.bz2
procedemos a aplicar el segundo parche o sea patch-2.4.22-rc2-ac1.bz2
(el cual ira encima del patch-2.4.22-rc2.bz2),
NOTA : el orden en el que se aplican los parches es vital, por que de
lo contrario el comando patch
te sacara error. Entonces el aplicar el siguiente parche sigue el mismo
procedimiento de arriba (se recomienda ejecutar el comando patch,
con la opcion --dry-run para hacer una prueba en seco).
Una vez que los dos parches se han alplicado correctamente, se procede
a compilar el kernel
Al hacer este proceso de parchado de un kernel, se puede obtener un
error como el siguiente:
can't find file to patch at input line 4
Perhaps you used the wrong -p
or --strip option? The text leading up to this was:
-------------------------- |diff -u --new-file --exclude-from
/usr/src/exclude --recursive linux.22-rc2/arch/alpha/ kernel/ entry.S
linux.22-rc2-ac1/arch/alpha/kernel/entry.S |---
linux.22-rc2/arch/alpha/kernel/entry.S 2003-08-09 16:00:36.000000000
+0100 |+++ linux.22-rc2-ac1/arch/alpha/kernel/entry.S 2003-06-29
16:10:35.000000000 +0100 --------------------------
File to patch:
esto significa que debes corregir la opcion -p en el comando
patch.
Reversando un parche
Haz aplicado muchos parches , y ahora quieres removerlos. Simplemente
usa la opcion -R en comando patch, con el mismo archivo de
parche, para reversarlo (nota, la página manual patch(1) es
menos clara en esto).
|
|
|
|
|
|
A
Quién puedo encontrar en #kernelnewbies ? |
|
|
| Nombre Real |
Nick |
Responsabilidad en el kernel |
| Anton Altaparmakov |
AntonA |
ntfs |
| Arjan van de Ven |
arjan |
kHTTPd,
Powertweak |
| Andre Hedrick |
ata |
IDE
guru |
| Jens Axboe |
axboe |
CDROM/DVD
layer |
| Ralf Baechle |
Bacchus |
Linux-MIPS |
| Ben LaHaise |
bcrl |
Administración de Memoria |
| Dave Jones |
davej |
encargado del
árbol 2.5-dj., Powertweak,
hacks
aleatorios |
| Erik Mouw |
erikm |
ARM
Linux, SA1100-Linux |
| f00f |
f00f |
Larting, jumping, y logging
|
|
| Greg Kroah |
gregkh |
USB |
| Christoph Hellwig |
hch |
Sistemas de archivos, kbuild, kernel cleanup |
| Jeff Dike |
jdike |
User Mode Linux |
| Jeff Garzik |
jgarzik |
Drivers para trabajo en red, PCI, kernel
cleanup |
| lxrbot |
lxrbot |
El canal oracle. Preguntale por
definiciones y usos en las fuentes del kernel, or query its factoid
database. |
| Thiago Rondon |
maluco |
Hacking aleatorio |
| Marcelo W. Tosatti |
marcelo |
Encargado 2.4 |
| Michael J. Cohen |
mjc |
Guadian del árbol de kernel -mjc |
| John Levon |
movement |
oprofile,
random minor hacking |
| Fabio O. Leite |
olive |
drbd, Alta Disponibilidad, heartbeat |
| Daniel Phillips |
phillips |
Sistema de archivos TUX2, implementación
ext2, administración de memoria hacking |
|
| Juan Quintela |
quintela |
Administración de memoria |
| Rik van Riel |
riel |
Administración de memoria |
| Russell King |
rmk |
ARM
Linux |
| Tigran Aivazian |
tigran |
Hacking aleatorio |
| Momchil Velikov |
velco |
VM hacker etc. |
| Alexander Viro |
viro |
guru del VFS |
| William Lee Irwin |
wli |
Hacking VM, bootmem, más
|
|
Por
qué tantos #define en el kernel que usan do { ... } while(0)? |
|
|
Hay un par de razones:
- (Dave Miller dice) Declaraciones vacias generan un warning del
compilador por eso es que ves #define FOO do { }
while(0).
- (Dave Miller dice) Esto te da un bloque basico en el cual se declaran
variables locales.
- (Ben Collins dice) Esto te permite usar macros más complejos en
código condicional. Imagina un macro de muchas lineas de código
como:
#define FOO(x) \
printf("arg es %s\n", x); \
haz_algo_util(x);
Ahora imagina usarlo así:
if (blah == 2)
FOO(blah);
Esto se interpretaria como:
if (blah == 2)
printf("arg es %s\n", blah);
haz_algo_util(blah);;
Como puedes ver, el if entoces solo reconce el
printf(), y el haz_algo_util() en la llamada es
incondicional (no con el condicional if), como lo
querias. Entonces, usando un bloque do{...}while(0), conseguirias
esto:
if (blah == 2)
do {
printf("arg es %s\n", blah);
haz_algo_util(blah);
} while (0);
Que es exactamente lo que querias.
- (Per Persson dice) Como Miller y Davis ambos dicen, quieres
una declaración de bloque entonces puedes tener muchas lineas de código y
declarar variables locales. Pero entonces lo natural seria
solo para ejemplo:
#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }
Sin embargo esto no funcióna en algunos casos. El siguiente código
significa una declaración ifcon dos bandas:
if(x>y)
exch(x,y); // Rama 1
else
haz_algo(); // Rama 2
Pero esto se interpretaria como una declaración if con
solo una rama:
if(x>y) { // declaración if con bandas sencilla!!!
int tmp; // La única banda consiste
tmp = x; // en el bloque
x = y;
y = tmp;
}
; // declaración vacía
else // ERROR!!! "error de analisis antes de else"
haz_algo();
El problema es el punto y coma (;) que esta directamente
despues del bloque.
La solución para esto es el sandwich del entre
el bloque do y while(0). Entonces tenemos
una declaración de línea sencilla con las capacidades de un bloque, pero no
es considerada, como declaración de bloque por el compilador.
Nuestra
declaración if se convierte en :
if(x>y)
do {
int tmp;
tmp = x;
x = y;
y = tmp;
} while(0);
else
haz_algo();
|
|
|
|
|
|
Cómo trabaja get_current() ? |
|
|
static inline struct task_struct * get_current(void)
{
struct task_struct *current;
__asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
return current;
}
get_current() es una rutina para conseguir acceso al
task_struct de la actual tarea en ejecución. Esta presenta
las usuales confusas caraterísticas del gcc inline assembly para hacer eso,
algo como lo siguiente :
| __asm__(
Esto significa que una parte de la inline assembly que el compilador debe
insertar en la salida de este código. El __asm__ es el mismo asm, pero
este no puede ser desactivado por banderas de línea de comando.
| "andl %%esp,%0
"%%" es un macro que expande a "%". "%0" es un macro
que expande a la primera especificacion de entrada/salida.
Por eso en este caso, toma el puntero a la pila (stack) (registro
%esp) y ANDs it dentro del registro que contiene
0xFFFFE000, dejando el resultado en el registro.
Basicamente, la pila (stack) de la tarea task_struct y una pila (stack) de tarea del
kernel ocupa un bloque de 8KB, el cual es un bloque de 8KB alineado, con
task_struct al comienzo y con el incremento de la pila (stack) desde el
fin hacia atras. Por eso puedes encontrar task_struct limpiando
en el fondo los 13 bits del apuntador al valor de la pila (stack).
| ; "
El punto y coma puede usarse para separar declaraciones assembly, tal como
lo hace el caracter sequencia escape de nueva línea("\n").
| :"=r" (current)
Esto especifica una salida constante (todo esto ocurre despues de los
primeros dos puntos, pero antes de los segundos). El '=' también especifica que
esta es una salida. La 'r' que un registro de proposito general
debera ser ubicado tal como esa instrucción puede ubicar la salida del valor
dentro de esta. El bit dentro de las comillas simples - 'current' - es la destinacion
encargada del valor de salida (normalmente una variable local)
una vez es retornado a la parte C.
| : "0" (~8191UL));
Esto especifica una entrada constante (todo esto ocurre despues de los
segundos dos puntos, pero antes de los terceros). El '0' referencia otra
constante (en este caso, la primera salida constante), diciendole que
el mismo registro o locacion de memoria debería usarse para ambos. El
'~8191UL' dentro de las comillas simples es una constante que debería se cargada
dentro del registro ubicado para el valor de salida antes de usar las
instrucciones dentro del bloque asm.
Mira también las paginas de información de gcc, Tema "Extensiones C", subtema
"Asm Extendido".
(Cortesia en su mayoría de David Howells de Redhat).
|
|
Cómo compilo un módulo ? |
|
|
Los modulos para el kernel deben construirse de forma segura
para que se compilen exitosamente en el kernel. La línea de compilació&;n
para la mayoría de modulos debería verse algo así :
gcc -o mimod.o -Wall -W -O2 -DMODULE -D__KERNEL__
-I/lib/modules/`uname -r`/build/include -c mi_mod.c
Debes usar la versión de gcc con la cual hayas compilado el
kernel. Debes especificar -O2 para hacer inline el código
necesario. Debes estar seguro de compilarlo opuesto las verdaderas
cabeceras del kernel opuesto que estas compilando. Usando (por defecto)
/usr/include/linux y amigos NO es suficiente.
El ejemplo de abajo asume que estas construyendolo opuesto al kernel en
ejecución, si no altera el parche con la opcion incluir -I.
MODVERSIONSModversions es el sistema de versiones para los simbolos
exportados del kernel. Para compilarlo opuesto :
- Debes añdir -DMODVERSIONS a la línea de compilación
- El primer include debe ser
- Si estas compilando un módulo con varios archivos fuente, debes
debes añadir #define __NO_VERSION__ en todos pero, solo en uno de los
archivos fuente .c. Notese que esto no es necesario con versiones recientes
del kernel.
- No debes incluir modversions.h directamente si tu
módulo esta incluido en las fuentes del kernel. Si lo estas construyendo
externamente, incluye el modversions.h correcto solo cuando las versiones de
los modulos estan habilitadas (esto es mejor que añadirlos a las lineas de
compilación como lo hace el kernel).
Por favor, también lee http://www.tux.org/lkml/,
especialmente preguntas 8-7 y 8-8
Empaquetamiento externoSi distribuyes tu módulo como
un paquete separado, es mejor incluir algún autoconf setup para
deteccion del kernel opuesto para compilar (por defecto a la ruta mensionada
/lib/modules/... ). Una vez que tu script configure, ha
encontrado el kernel, puede incluir Rules.make para usar las reglas
de banderas correctas para el compilador etc. (esto es especialmente
para banderas específicas de cada arquitectura). El módulo CIPE, por ejemplo, hace
esto (vease parches).
La forma adecuada de compilar modulos
La forma confiable y enfocada a largo plazo de compilar modulos es dejar que el sistema
de compilación del kernel haga el trabajo duro por ti. Usa autoconf o un mecanismo
similar para localizar el árbol de código fuente del kernel (por defecto en la ruta siguiente a /lib/ modules/). Lee Documentation/kbuild, para ver como debería verse tu Makefile, para que el módulo se compile por sí mismo, y entonces cuadra una llamada desde el directorio base del kernel, es necesario especificar SUBDIRS. Por ejemplo, si tu Makefile generado esta en
/home/usuario/src/mimodulo-0.1/módulo/, y el código fuente del árbol de kernel de los usuarios
esta en /usr/src/linux-2.5/, entonces el fragmento de Makefile podria verse algo así:
kernel_module:
$(MAKE) -C /usr/src/linux-2.5 SUBDIRS=/home/usuario/src/mimodulo-0.1/módulo/ modules
Esto establecera correctamente todas las banderas y tendra vigencia en el futuro usando la
maquinaria de compilación del kernel por si mismo para generar el módulo.
Puedes encontrar
un ejemplo simple para los kernels 2.6 aquí:
sillymod.tar.gz, se compila de la forma estandar, "./configure, make, make install".
|
|
|
|
|
|
Qué significa un lsmod con cuenta -1 ? |
|
|
Esto significa que el módulo ha declarado la función
->can_unload().
Los modulos normales se referencian vía cuenta.
MOD_INC_USE_COUNT y amigos. Modulos con la función
can_unload(), sin embargo, han decidido administrarse con el
uso del módulo vía función, la cual retorna -EBUSY cuando
el módulo no es descargable.
Un valor de -1 significa que lsmod es incapaz de determinar la
descargabilidad del módulo, y la única forma de hacerlo es tratar con
rmmod.
|
|
|
|
|
|
Cuál es la diferencia entre extern y static inline ? |
|
|
Permite a Linus explicar :
-
"static inline" s.pngica "Tenemos que tener la función, si la usas
pero no la haces inline, entoces se hara una versión estática de esta unidad de
compilación"
- "extern inline" significa "Actualmente _tengo_ un externa para esta función,
pero si quieres tenerla inline, aquí esta la versión-inline"
Pero también mira funciónes
Inline en C.
|
|
|
|
|
|
Qué es System.map ? |
|
|
System.map es un archivo (producido vía nm) el cual con tiene los
nombres de los simbolos y las direcciones del kernel binario de linux, vmlinux.
Se usa principalmente en depuracion. Si aparece un mensaje "oops"
en el kernel, la utilidad ksymoops puede ser usada para decodificar el mensaje
en algo util para los desarrolladores. ksymoops hace uso de
System.map para mapear valores de la PC hacia valores simbolicos.
Notese que los kernel 2.5 continen un decodificador de "oops" llamado kksymoops,
el cual no necesita System.map
Puedes recibir warnings de System.map si este esta desactualizado.
Esto no afectara la normal ejecución pero es mejor mantener una copia en caso
de si hay un bug el kernel / falla de hardware. Note que ps l
usa System.map para determinar el campo WCHAN (puedes especificar un archivo
mapa con la variable de entorno PS_SYSTEM_MAP). Las Utilidades
buscan en una serie de lugares estandar para este archivo tales como
/boot/System.map
y /usr/src/linux/System.map
|
|
|
|
|
|
Qué pasa con los archivos de cabecera del kernel ? |
|
|
En cualquier distribución, hay dos tipos de cabeceras del kernel :
Cabeceras de sistema del kernelActualmente estas cabeceras
son usadas por el sistema. Estas son las cabeceras con las cuales se compila las utilidades de espacio de usuario. Deben estar instaladas para compilar programas
de espacio de usuario.
Las cabeceras usualmente se encuentran en /usr/include/asm y en
/usr/include/linux. Son copias nunca deberian
modificarse (a menos que actualices una librería C). Esas
cabeceras continenen código para compatibilidad etc. para permitirles
ser usadas con una variedad de kernels en ejecución, y conceptualmente
son parte del paquete glibc. Usualmente pueden ser encontradas en el
paquete/RPM. kernel-headers o en libc6-dev
Cabeceras de fuente del kernelSon parte del paquete de las
fuentes del kernel. Estas
nunca deben usarse para compilación de programas de
espacio de usuario. Las viejas distribuciones usualmente hacian
/usr/include/linux y
/usr/include/asm vinculos simbolicos a las partes correctas del
árbol fuente del kernel, instaladas en /usr/src/linux. Esto esta mal
hecho - programas de espacio de usuario deben usar
cabeceras, convenientemente modificadas.
Conversely, cuando se compila el kernel o modulos para este, estas
cabeceras deben ser usadas. Esto es importante cuando se compila modulos
empaquetados externamente - la compilación del módulo debería ir en el lugar
correcto para las cabeceras (por e.j. añadiendo -I /lib/modules/`uname
-r`/build/include).
Lee la
explicación de Linus a esta situación.
|
|
|
|
|
|
Cuales son los multiples arboles de kernel ? |
|
|
- -ac
- Encargado:
Alan Cox
Parches pendientes para enviarlos a Marcelo
(para la serie 2.4), extra adiciones, y correciones. etc.
- -mm
- Encargado:
Andrew Morton
Elegantes nuevas caracteristicas y correciones
enfocadas al hacking del subsistema VM.
- -mjc
- Encargado:
Michael Cohen
Mas correcciones
extra para la serie 2.4 del kernel, implementaciones VM etc.
Usualmente contiene
parches más experimentales aun no propiamente listos para el 2.4.
- -aa
- Encargado:
Andrea Arcangeli
Actualizaciones para VM, multitud de correciones
y varias implementaciones de Andrea.
- -dj
- Encargado:
Dave Jones
Adelanta correciones del 2.4 para la
serie 2.5 . (a slightly less bloody bleeding
edge)
- -ck
- Encargado:
Con Kolivas
Una serie de parches estables para el 2.4, enfocados al
rendimiento del scheduler y la VM, con un optimización especifica del desktop,
para mejorar la respuesta del sistema.
- -osdl
- Encargado: open source development labs
- Para centros de datos o carrier grade linux, incluye especialmente optimizaciones
para grandes maquinas y alto rendimiento en bases de datos.
- -rmap
- Encargado: Rik van Riel
rmap realiza en su mayoría un mapeo inverso de marcos de páginas
a mapeos virtuales, con el propósito de hacer una VM más
predecible, para liberarse de algunos de los peores casos de comportamiento de la VM
y facilitar las cosas. Los mapeos inversos proveen una infraestructura para hacer lo
más flexible posible la VM, lo cual significa que las estrategias en -rmap
cambian a menudo.
|
|
Cómo intercepto llamadas de sistema ? |
|
|
Puedes usar algo como el el kit de herramientas para trazado de Linux
probablemente.
Hay también un horrible hack basado en la modificación de las entradas
en la tabla de llamadas del sistema. Esto es altamente no recomendado, no es
seguro contra la descarga del módulo, esto no es independiente de la arquitectura,
y esto es incorreto de cualquier forma.
Habiendo dicho eso, esto parece tarea común para el aprendizaje
del hacking en el kernel. Mira el módulo syscalltrack para
algo de código que actualmente haga esto..
Basicamente cada valor apuntado en la tabla global sys_call_table es
modificado para apuntar a una nueva dirección proporcionada por el módulo del
kernel, de esta forma cuando el proceso hace la llamada de sistema,
terminará la rutina. Puedes entonces llamar al antiguo valor
guardado de la llamada de sistema para procesar el pedido y despues
recolectar cualquier información que necesites.
Esto falla horriblemente para la llamada de sistema execve, y hay una muy
buena razón para esto. Echemos un vistazo al prototipo de
sys_execve() :
asmlinkage int sys_execve(struct pt_regs regs)
Notese que el argumento - no es un puntero ! Tu intento
de intercerptar sys_execve no funcionara. Este
argumento indica que los registros de los procesos han sido guardados
en la pila (stack). El código dentro de sys_execve actualmente modifica esas locaciones
de la pila (stack) para ubicarlas el valor del registro del PC al comienzo del nuevo
ejecutable - Por eso debes permitir el acceso al código en punto original
de la pila (stack) !
Por ejemplo el código que hace la modificación de los registros, mira
start_thread() llamada desde load_elf_binary().
La forma más simple de get around este problema es llamando a
do_execve() en vez del antiguo valor guardado en el punteo al valor sys_execve pointer value,
duplicando el código del kernel sys_execve(). Suena feo ? Por favor
no hagas esto en el código verdadero. Si quieres prover algún código en
el módulo que el kernel necesite llamar, provee un hook en el código del
kernel, como un parche, despues un módulo encima de este (un ejemplo de
esto es sys_nfsservctl()).
Notese que Linus quito el exportado de sys_call_table en los
kernel 2.5.
|
|
|
|
|
|
Puedo usar funciones de librería en el kernel ? |
|
|
Librerias de sistema (tales como glibc, libreadline, libproplist,
cualquiera que sea) que estan tipicamente disponible para los programadores
de espacio de usuario, no lo estan para los programadores del kernel.
Cuando un proceso esta siendo cargado, el cargador carga alguna librería
dependiente en el espacio de dirección del proceso.
Ninguno de estos mecanismos esta disponible para los programadores del
kernel, olvidate del las librerías ISO C, las unicas cosas disponibles
son las que ya estan implementadas (y exportadas) en el kernel y lo que
tu puedas implementar.
Mira que es posible "convertir" librerías para trabajar en
el kernel; sin embargo, no se acomodaran bien, el proceso es tedioso y
esta sujeto a errores, y posiblemente haya problemas con la el manejo
de la pila (stack) (el kernel esta limitado a una pequeña cantidad de espacio en pila (stack),
mientras que los programas de usuario no tienen esa limitacion) causando
corrupcion aleatoria de memoria.
Muchas de las funciónes usualmente más usadas ya han sido
implememtadas en el kernel, a veces en las versiones "ligeras"
las cuales no son tan completas como las demas. Debes estar seguro de
filtrar las cabeceras para alguna función que puedas usar antes de escribir
tus propias versiones de los scratch. Algunas de las más comunmente usadas
estan en include/linux/string.h.
Cuando sientas la necesidad de usar una función de librería,
deberias considerar su diseno, y preguntarte si puedes migrar todo o parte
de ese código de espacio de usuario.
|
|
|
|
|
|
Hay algún buen IDE (Entorno de Desarrollo Integrado)?
Cómo manejo todo ese código? |
|
|
Cuando trabajas con gran cantidad de código fuente, como lo es el kernel,
seguramente te ayudara tener algunas herramientas de software parar entender
como los programadores se acomodan a ambos. Quizas la herramienta más importante
es un buen editor de text para el programador. Elecciones populares son
emacs y cualquier clon de vi, tal como
vim.
Generalmente, los editores de texto escritos para programadores son programables
y tienen caracteristicas como selección de sintaxis, despliege de texto, búsqueda
de patrones y facil integración con herramientas de manejo de código, tales
como make(1), cvs(1), reformateo de texto, búsqueda en paginas de manual y más.
La herramienta más popular es la que busca rapidamente, usos, definiciones
y declaraciones de simbolos C. grep(1) esta casi siempre disponible, y la versión
más poderosa, egrep(1), es muy util conocerla. Pero grep(1), requiere búsqueda
de todos los archivos en todas las busquedas. Herramientas como
cscope, freescope, etags,
ctags, y idutils
construyen bases de datos para la búsqueda de simbolos C. Cada una tiene
su propia idiosincracia y caracteristicas. Algunas se integran mejor con el
editor de tu preferencia. (busca especialmente plugins para
la integración.)
cgvg es otra opcion,
la cual no aparece como una base de datos para busquedas rapidas.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|