¿Cuál es la diferencia entre estas dos formas de ensamblador en línea en C?
-
21-09-2019 - |
Pregunta
Antecedentes: He recibido el encargo de escribir un programa de recolección de datos para un rel="noreferrer"> , que se ejecuta un sistema operativo DOS de propiedad que se puede ejecutar archivos ejecutables compilados para 16 bits MS DOS, aunque con algunas restricciones. Estoy usando el compilador Marte Digital C / C ++, que parece estar funcionando muy bien.
Para algunas cosas que puedo usar bibliotecas de C estándar, pero otras cosas como dibujar en la pantalla de la unidad de requerir el código de montaje. Los ejemplos de montaje dadas en la documentación del dispositivo son diferentes de cómo me enseñaron a utilizar el código de montaje en línea en C / C ++. Para referencia, BYTE
en los ejemplos siguientes es de tipo unsigned char
.
muestra del ejemplo de código se me 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, ®s, ®s);
}
Como 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
}
}
Las dos formas parecen funcionar, no he encontrado un problema con cualquiera de los enfoques hasta el momento. Se considera una forma mejor que el otro para la programación en DOS? ¿La función de int86
manejar algo por mí que yo no estoy manejando mi mismo en mi propio código de montaje en el segundo ejemplo?
Gracias de antemano por cualquier ayuda.
Solución
Cuando se utiliza la llamada a la función int86
, que es una función de biblioteca C de tiempo de ejecución que establece los registros y emite una función DOS int
errupt. Ambos métodos son realmente lo mismo con una excepción, cuando se utiliza ensamblador en línea, el código es en realidad incrustado en el código objeto cuando se compila y vinculado.
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 está en usted para asegurarse de que hay suficiente espacio de pila cuando se utiliza ensamblado en línea, mientras que la biblioteca de tiempo de ejecución C se encarga de la asignación de espacio de pila cuando la creación de 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 era extremadamente popular entre la suite de edad Turbo C de compiladores y en Microsoft, estoy hablando de los viejos compiladores antes Win 3.1 salió.
Hablando de la interrupción 0x10, que es responsable de la salida de vídeo, si no recuerdo mal, en ese momento, destruido el registro bp
de algunos BIOS y la solución era hacer esto:
__asm{
push bp;
}
/* set up the registers */
int86(0x10, ®s, ®s);
__asm{
pop bp;
}
Puede averiguar las amplias funciones de BIOS en la lista de interrupción de Ralph Brown aquí . También v2.1 HelpPC puede ayudar también, encontró aquí .
Otros consejos
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 la espalda, simplemente compilar su programa y examinar el código ensamblador generado
Al llamar int86, su código permanece en forma de C. De cualquier, que está escribiendo el píxel haciendo una interrupción del sistema.
Si usted tiene un mucho de píxeles para escribir, y se inicia seriamente golpear a los problemas de velocidad, puede haber una manera más directa (y mucho menos seguro pero posiblemente valga la pena) para escribir directamente al píxel la memoria.
Los dos fragmentos de código obtener el mismo resultado. La gran ventaja de la primera de ellas es que hay alguna probabilidad de que usted todavía será capaz de utilizarlo cuando se cambia compiladores. Y que no pisa fuerte en un registro que generador de código de compilador de la 'C' estaba usando para otro propósito. Algo que definitivamente se olvide de cuidar de en el fragmento asm.
Se 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 las variables son asignados a los registros, cambios no deseados de los valores pueden dar lugar a difíciles de encontrar errores. int86 (0x10, y reglas, y reglas); guarda registros y los restaura después de ejecutar el software de interrupción.
Algunos compiladores aceptan instrucciones para definir una lista clobber (registros que se deben guardar y restaurar). Por lo general, una sección ensamblador debe guardar registros y banderas que serán cambiados con empuje y restaurarlos usando pop, ya sea por el compilador o usted mismo. Por lo tanto el primer ejemplo debe ser preferido.
Eso no es ensamblado en línea, es C. de muy bajo nivel C, utilizando una función para causar la interrupción, pero todavía C.
Esta página tiene algún tipo de documentación (por el compilador DJGPP, el tuyo puede funcionar de forma diferente), incluyendo la estructura utilizada para representar los registros. Asimismo, toma nota:
Tenga en cuenta que, a diferencia de la __dpmi_int función, peticiones que pasan a través funciones int86 y similares están especialmente procesado para que sean adecuado para invocar en modo real interrumpe de modo protegido programas. Por ejemplo, si un particular, rutina toma un puntero en BX, int86 espera que coloques una (modo protegido) puntero en EBX. Por lo tanto, int86 debe tener un apoyo específico para cada interrumpir y función se invoca este camino. Actualmente, sólo es compatible con una subconjunto de todas las interrupciones disponibles y funciones [...]