Práctica 3. Interfaz con el lenguaje C



Objetivos

La práctica consiste en la realización de la siguiente tarea:

La práctica se valorará en función de la interacción entre el lenguaje C y el ensamblador, más que por un gran desarrollo en C.

No se permite el uso de código ensamblador insertado en funciones de C.

Es obligatorio el uso de paso de parámetros entre C y ensamblador.

Se recomienda dejar la implementación del formato .s19 para el final, una vez que ya esté todo funcionando para el formato binario.

(*) También se puede usar el driver entregado en la primera práctica. De esta manera se facilitan las pruebas y permite que si a algún grupo no le ha funcionado correctamente la P2 pueda seguir trabajando sin problemas con la práctica 3.

De todas formas, se valorará positivamente el uso del driver propio.


Qué hay que hacer:

1.    Escribir en ensamblador un programa aparte o una librería de conexión entre la parte C y el driver. Este programa aparte o librería deberá incluir una llamada a cada función correspondiente a  cada servicio del driver (cada valor de AH distinto).
2.    Escribir la interfaz en C (descrita en el inicio de este documento).
3.    "Linkar" el programa en C y la librería en ASM en un programa. Para ello se deberá usar la herramienta tcc (Turbo C Compiler)
4.    Hacer un makefile que compile y haga el "linkado".


Artículo muy interesante para entender como se maneja la pila desde C y ensamblador

                Smashing the stack for fun and profit, por Aleph One


Ejemplo completo de programación mixta (ASM+C) paso a paso:

En muchas ocasiones se necesita el calculo a*b/c con números enteros. El problema consiste en el posible desbordamiento del a*b incluso si el resultado a*b/c cabe en un int. Por tanto, dicho calculo hay que hacerlo en ensamblador o con tipo long, que es mas costoso. Se necesita hacer una función en ensamblador, que calcula a*b/c.

1. Elegimos el prototipo de la función:
int mul_div(int a,int b,int c);
Escribimos dicho prototipo en el fichero mul_div.h


2. Necesitamos el esqueleto de esta función en ASM:
Escribimos en un fichero llamado mul_div.c:

int mul_div(int a, int b, int c) {
    return a+b-c; // notar la diferencia en el func. Es un stub
}
compilamos, generando ASM

tcc -S mul_div.c


3. Escribimos el programa en ensamblador, utilizando el esqueleto generado por tcc en el paso previo:
edit mul_div.asm

En el cuerpo del programa cambiamos las instrucciones necesarias:

mul_div proc near
    push bp
    mov bp,sp
    ...    
    mov ...,[bp+4] ; el a
    add ...,[bp+6] ; el b
    sub ...,[bp+8] ; el c
    ...
    pop bp
    ret
mul_div endp
...
cambiamos a:

mul_div proc near
    push bp
    mov bp,sp
    mov ax,[bp+4] ; el a
    cwd
    imul [bp+6] ; el b
    idiv [bp+8] ; el c
    pop bp
    ret
mul_div endp


4. Compilamos el modulo ASM con opciones 'case sensitive'
   4.1. Encontramos la opción:
   tasm
   4.2. Compilamos (los ... es la opción):
   tasm -m... mul_div.asm


5. Escribimos un programa en C (muldiv.c) que comprueba la función:
#include <stdio.h>
#include "mul_div.h"

int main() {
    for(;scanf("%d%d%d",&a,&b,&c)==3;) {
        printf("%d %d\n",mul_div(a,b,c),a*b/c);      
    }
    return 0;
}


5. Compilamos:
tcc muldiv.c

(mensaje de error por falta de la función mul_div)

tcc muldiv.c mul_div.obj

6. Comprobamos.

A>muldiv.exe

Comprobar con las entradas 2 3 2 y 512 512 10.
 

7. Hacer makefile:
Hemos ejecutado los comandos

 tasm /mx mul_div

con entrada mul_div.asm y salida mul_div.obj y

 tcc muldic.c mul_div.obj

con entrada muldiv.c, mul_div.obj y salida muldiv.exe.
muldiv.c contiene el ‘include’ de mul_div.h. Por tanto el makefile seria:
----------------------------------------------------------
muldiv.exe: muldiv.c mul_div.obj mul_div.h
        tcc muldiv.c mul_div.obj

mul_div.obj: mul_div.asm
         tasm /mx mul_div

----------------------------------------------------------

escribimos el makefile (edit makefile) y comprobamos:

del *.obj
make -f makefile
 

Ejercicios:

       1.    Quitar todo lo no necesario en el fichero mul_div.asm.
       2.    Hacer el link separado de la compilación en el ejemplo.
       3.    Comprobar el programa con entrada 512 512 5 .
       4.    Hacer el programa mul_div con tipo unsigned. Comprobar 512 512 5.
       5.    Hacer mul_div en modelo de memoria large.


Notas de ayuda:     El Universo Digital del PC: El ensamblador y el lenguaje C. Capítulo 13  de un buen libro digital



Plazo de entrega : La presentación y evaluación de esta práctica será según consta en el calendario. El nombre de cada fichero deberá seguir las normas aplicadas para la práctica 2, enviando un único fichero comprimido tipo zip.