2010-01-18 21 views
7

Antecedentes: me han encargado escribir un programa de recopilación de datos para Unitech HT630, que ejecuta un sistema operativo DOS propietario que puede ejecutar ejecutables compilados para MS DOS de 16 bits, aunque con algunas restricciones. Estoy usando el compilador Mars C/C++ Digital, que parece estar funcionando muy bien.¿Cuál es la diferencia entre estas dos formas de ensamblador en línea en C?

Para algunas cosas puedo usar bibliotecas C estándar, pero otras cosas como dibujar en la pantalla de la unidad requieren código de ensamblaje. Los ejemplos de ensamblaje que figuran en la documentación del dispositivo son diferentes de cómo me enseñaron a usar el código de ensamblaje en línea en C/C++. Como referencia, BYTE en los ejemplos siguientes es del tipo unsigned char.

muestra del código de ejemplo que se le dio:

#include <dos.h> 

/* Set the state of a pixel */ 
void LCD_setpixel(BYTE x, BYTE y, BYTE status) { 
    if(status > 1 || x > 63 || y > 127) { 
    /* out of range, return */ 
    return; 
    } 
    /* good data, set the pixel */ 
    union REGS regs; 
    regs.h.ah = 0x41; 
    regs.h.al = status; 
    regs.h.dh = x; 
    regs.h.dl = y; 
    int86(0x10, &regs, &regs); 
} 

Cómo Siempre me enseñaron a usar ensamblador en línea:

/* Set the state of a pixel */ 
void LCD_setpixel(BYTE x, BYTE y, BYTE status) { 
    if(status > 1 || x > 63 || y > 127) { 
    /* out of range, return */ 
    return; 
    } 
    /* good data, set the pixel */ 
    asm { 
    mov AH, 41H 
    mov AL, status 
    mov DH, x 
    mov DL, y 
    int 10H 
    } 
} 

Ambas formas parecen funcionar, no he encontrado un problema con cualquiera de los enfoques hasta el momento. ¿Se considera que una forma es mejor que la otra para la programación de DOS? ¿La función int86 maneja algo para mí que no estoy manejando en mi propio código de ensamblado en el segundo ejemplo?

Gracias de antemano por cualquier ayuda.

+0

El título es engañoso/incorrecto. No hay un asm en línea en la primera versión, solo un contenedor de llamada de función alrededor de la llamada al sistema. (O un compilador podría implementar 'int86()' como intrínseco y en línea el asm correcto). –

Respuesta

9

Cuando utiliza la llamada a la función int86, es decir, una llamada a la biblioteca C runtime que configura los registros y emite una función de error DOS int. Ambos métodos son realmente iguales con una excepción, cuando se usa el ensamblador en línea, el código está realmente integrado en el código objeto cuando se compila y se vincula.

ensamblador en línea sería considerado más rápido, ya que no tiene la sobrecarga generada en llamar a la biblioteca de tiempo de ejecución C para invocar el DOS de interrupción para usted. La responsabilidad recae en usted para asegurarse de que haya suficiente espacio de pila al usar el ensamblaje en línea, mientras que la biblioteca de C Runtime se ocupa de asignar el espacio de pila al configurar los registros antes de invocar la función int86.

El int86 es una manera de hacer que sea más fácil para invocar DOS interrumpe. Esto fue extremadamente popular entre los antiguos compiladores de Borland Turbo C y en Microsoft, estoy hablando de compiladores antiguos antes de que saliera Win 3.1.

Hablando de la interrupción 0x10, que es responsable de la salida de vídeo, si no recuerdo mal, en ese momento, algunos BIOS del destruyeron el registro bp y la solución era hacer esto:

__asm{ 
    push bp; 
} 
/* set up the registers */ 
int86(0x10, &regs, &regs); 
__asm{ 
    pop bp; 
} 

Puede descubra las funciones extensas de BIOS en la lista de interrupción de Ralph Brown here. También HelpPC v2.1 puede ayudar también, encontró here.

+0

Creo que tenía una copia de la lista de interrupción de Ralph Brown en la universidad ahora que lo pienso y no tengo idea de qué hice con ella. Parece que olvidé que este recurso increíble existió, ¡gracias! Esto es muy útil. –

+0

+1 por mencionar la lista de interrupciones de Ralph Brown y el HelpPc –

0

Eso no es ensamblado en línea, es C. Muy bajo nivel C, utilizando una función para causar la interrupción, pero aún C.

This page tiene algún tipo de documentación (por el compilador DJGPP, la suya podría funcionar de forma diferente), incluida la estructura utilizada para representar los registros. Asimismo, toma nota:

Tenga en cuenta que, a diferencia de la función __dpmi_int , peticiones que pasan por int86 y funciones similares se procesados ​​de forma especial para que sean adecuado para invocar de modo real interrupciones de modo protegido programas . Por ejemplo, si una rutina particular de toma un puntero en BX, int86 espera que ponga un puntero (en modo protegido) en EBX. Por lo tanto, int86 debe tener soporte específico para cada interrupción y función que invoca este modo . Actualmente, se admite sólo un subconjunto de todos los interrupciones disponibles y funciones [...]

+0

esto es cierto para DJGPP compilador de C, como int86 no es una función estándar no es dado que el compilador Marte digital funciona de la misma manera, es posible que haya más o menos restricciones – Alon

1

la primera forma es más fácil de leer que también cuenta para algo ;-)

si desea saber si int86 está haciendo algo detrás de su espalda, solo compile su programa y examine el código ensamblador generado

+0

"La primera forma es más fácil de leer". ¿Es? –

+0

Creo que la forma es más "legible" que la otra es una cuestión de opinión personal, porque personalmente encuentro la segunda más legible, pero ambas son comprensibles. Diseccionar el código compilado sería algo así como un último recurso, si alguien no tuviera la respuesta para mí aquí, seguramente seguiría esa ruta. –

+0

El primer formulario es más legible por los compiladores que usan un formato diferente para el ensamblaje en línea. Pero puede preocuparse por la sobrecarga de la llamada de función innecesaria, además de abordar los elementos de la unión 'REGS', luego presumiblemente el' int86' copiando todos los registros (todos los definidos en la unión, no solo los que usa) de memoria, luego copiarlos todos de nuevo (que luego descartar). –

1

Al llamar a int86, su código permanece en C. De cualquier forma, está escribiendo el pixel haciendo una interrupción del sistema.

Si usted tiene un montón de píxeles para escribir, y empezar a golpear seriamente los problemas de velocidad, puede haber una manera más directa (y mucho menos seguro pero posiblemente valga la pena) para escribir directamente en la memoria de píxeles.

+0

Puede haber un punto en el que tenga muchos píxeles para escribir, ya que el cliente está debatiendo una pantalla de bienvenida al inicio de la aplicación. Por ahora, solo necesito esto para dibujar una línea extraña en la pantalla. Ese problema puede terminar siendo su propia pregunta cuando llegue el momento. –

+0

@Heather: Sí, busqué tu máquina, y la pantalla es monocromática y minúscula, así que dudo que los gráficos sean un cuello de botella. –

1

Ambos fragmentos de código obtener el mismo resultado. La gran ventaja de la primera es que existe la posibilidad de que puedas usarla cuando cambies de compilador. Y que no pise un registro que el generador de código del compilador 'C' estaba usando para otro propósito. Algo de lo que definitivamente te olvidas de ocuparte en tu fragmento asm.

+0

. Sospeché que no estaba haciendo algo que debía estar haciendo en el bloque asm. Gracias. –

1

debe comprobar el manual de compilación para averiguar quién es responsable de restaurar los valores de registro después de una sección de montaje en línea. Dado que sus variables están asignadas a los registros, los cambios involuntarios de los valores pueden dar lugar a errores difíciles de encontrar. int86 (0x10, & regs, & regs); guarda registros y los restaura después de ejecutar la interrupción del software.

Algunos compiladores aceptan instrucciones para definir una lista clobber (registros que se deben guardar y restaurar). Por lo general, una sección de ensamblador debe guardar los registros y las marcas que se cambiarán con push y restaurarlos mediante pop, ya sea por el compilador o usted mismo. Por lo tanto, debe preferirse el primer ejemplo.

+0

Estoy de acuerdo con int86: creo que usaré este enfoque para estar seguro a menos que la velocidad se convierta en un problema real, gracias :) –

Cuestiones relacionadas