lunes, 12 de enero de 2009

Mezclando códigos de 16 y de 32 bits

Los módulos de un programa escritos para funcionar en procesadores IA-32 pueden ser de 16 o de 32 bits, aunque funcionan de forma mas eficiente cuando ejecutan programas de 32 bits. Pueden ejecutar módulos de programas de 16 bits en el modo real-address, en el modo virtual-8086, en el modo de administración del sistema (SMM), como una tarea en modo protegido (si el código, los datos y los segmentos de pila para esa tarea están configurados como segmentos de 16 bits), integrando segmentos de 16 y de 32 bits en una tarea única en modo protegido, y por último integrando operaciones de 16 bits en segmentos de código de 32. Los modos real-address, virtual-8086 y SMM son nativamente modos de 16 bits. Lo siguiente son los mecanismos usados para distinguir y para dar soporte a segmentos y operaciones de 16 y 32 bits:
- La bandera D en los descriptores de segmentos de código.
- La bandera B en los descriptores de segmentos de pila.
- Las puertas de llamada de 16 y 32 bits, de interrupción, y de trampa.
- Los prefijos de instrucciones de tamaño de operando y de tamaño de dirección.
- Los registros de propósito general de 16 y de 32 bits.
La bandera D determina el tamaño de operando y de dirección por defecto para las instrucciones de un segmento de código. La bandera B especifica el tamaño del puntero de la pila usado por el procesador para referencias implícitas en la pila.
Los siguientes dos prefijos de instrucción permiten mezclar operaciones de 32 y de 16 bits dentro de un segmento: El prefijo de tamaño de operando (66H) y el prefijo de tamaño de dirección (67H). Siempre que sea posible se debe usar segmentos de código de 32 bits, ya que funcionan mucho mas rápido. Si un sistema operativo está diseñado en 16 bits, probablemente no funcionen los módulos en 32. Si un código se diseña para funcionar en el modo real-address, en el modo virtual-8086, o en el modo SMM, tiene que ser de 16 bits.
A los segmentos de datos se puede acceder desde segmentos de 16 y de 32 bits. Cuando un segmento de datos es mas largo que 64 KBytes se comparte a lo largo de segmentos de código de 16 o de 32 bits, los datos a los que se debe acceder desde el segmento de 16 bits tiene que ser localizado dentro de los primeros 64 KBytes del segmento de datos. Esto se debe a que los punteros de 16 bits pueden apuntar como máximo a los 64 KBytes del segmento. Una pila que ocupa menos de 64 KBytes puede ser compartida por segmentos de código de 16 y de 32 bits.
Hay 3 formas de que un procedimiento en un segmento de 16 bits llame de forma segura a un código de 32 bits:
- Hacer la llamada a través de una puerta de llamada de 32 bits.
- Hacer una llamada de 16 bits a un procedimiento de interface de 32 bits. Después el procedimiento de interface hace una llamada de 32 bits al destino deseado.
- Modificar el procedimiento de 16 bits insertando un prefijo de tamaño de operando antes de la llamada, para cambiarla por una llamada de 32 bits.
Hay otras tres formas de hacer una llamada de forma segura desde un segmento de código de 32 bits a uno de 16:
- Hacer la llamada a través de una puerta de llamada de 16 bits (el valor EIP de la instrucción CALL no puede exceder de FFFFH)
- Hacer una llamada de 32 bits a un procedimiento de interfaz de 16, y que éste haga otra al destino deseado.
- Modificar el procedimiento de 32 bits insertando un prefijo de tamaño de operando antes de la llamada. Hay que asegurarse de que el offset de retorno no exceda FFFFH.

No hay comentarios: