Práctica: Interfaz C S.E.T.I. 1 Enunciado: Queremos realizar un programa en C que maneje ventanas emergentes, pero queremos que el dibujado de las mismas sea lo más rápido posible, por lo que nos hemos decidido a escribir la rutina en ensamblador. El fichero Makefile contiene lo siguiente: #Fichero makefile. windows.exe: main.obj fastwin.obj bcc –ml -v -ewindows.exe main.obj fastwin.obj main.obj: main.c bcc –ml –v -c main.c fastwin.obj: fastwin.asm nasm –g -fobj fastwin.asm donde tenemos que tener cuidado en introducir tabuladores para sangrar el texto. El fichero main.c simplemente comprueba el funcionamiento de dicha rutina haciendo aparecer unas 2000 ventanas de posición y color variables. Notar cómo la subrutina en cuestión se declara como externa para ser enlazada posteriormente. #include <stdio.h> #include <stdlib.h> #include <time.h> // Función externa realizada en ensamblador, que será enlazada // con este código extern void windows_at(long int, long int, long int, long int, int); void main() { int i; randomize(); for( i=0;i<2000;i++ ) windows_at(random(40), random(10), 30, 10, random(127)); } Para la realización de la subrutina en ensamblador hemos de tener en cuenta algunos detalles: El nombre de las funciones en C van precedidas de un guión bajo (_). Así en nuestro caso deberemos declarar como global la etiqueta _windows_at en el programa ensamblador y sin guión bajo en el programa en C. El esqueleto del programa en ensamblador (fastwin.asm) se muestra a continuación: [section .text] [global _windows_at] ; La función es: ; windows_at(long int x, long int y, long int sizex, ; long int sizey, int attribute); ; ; donde: ; ebp + 0 EBP viejo ; ebp + 4 Dirección de retorno far ; ebp + 8 Primer parámetro (4 bytes) ; ebp + 12 Segundo parámetro (4 bytes) ; ebp + 16 Tercer parámetro (4 bytes) ; ebp + 20 Cuarto parámetro (4 bytes) ; ebp + 24 Quinto parámetro (2 bytes) ; Ojo: En el compilador Borland C de MSDOS ; ; Tipo C Tamaño ; -------------------------------------------------------; char 2 Ocupa 1 pero se alinea a dos byte ; int 2 (en Linux es 4) ; long int 4 ; short 2 ; int* 4 primero el desplazamiento ; de 16 bits y el selector 16 bits ; de donde se encuentra la variable _windows_at: push ebp mov ebp,esp pushad .... Ej: .... popad pop ebp retf ; Guardo el puntero base ; Apunto a la cima de la pila ; Guardo los registros que uso mov eax,[ebp+20] ; Lee sizey ; Recupero los registros que uso ; Recupero el puntero base ; Retorno far Si la rutina devolviera un valor entero lo haría modificando el registro EAX. Dado que la rutina del ejemplo no devuelve ningún valor, EAX recupera su valor al salir. Notar que el C utiliza una llamada lejana (far) para acceder a nuestra función, luego hay que hacer un retorno far (retf) Para acceder a la pantalla en modo texto (80x25 caracteres) hay que saber que está situada en la dirección 0B800h:0000h, luego habrá que apuntar al segmento correspondiente y calcular el desplazamiento correcto. Cada palabra que se escribe representa lo siguiente: Byte bajo: el código ASCII que queremos pintar. El espacio es el código 32. Byte alto: atributos de color del carácter calculado como sigue: Atributo = 128*Parpadeo + 16*Color_fondo + Color_primer_plano donde Parpadeo = 0 ó 1, Color_Fondo = 0..7, Color_primer_plano = 0..15 Primeramente realizar la subrutina windows_at() de forma que rellene un recuadro situado a partir de la posición (x,y) y con un tamaño (sizex,sizey) escribiendo caracteres en blanco con el atributo de color seleccionado. Intentar que la ventana esté recuadrada con una línea sencilla. Para ello podéis emplear los caracteres: 218, 196, .., 196, 191 para el marco superior; 179, 32, .., 32, 179 para la zona intermedia; y 192, 196, .., 196, 217 para el marco inferior.