Contactos

Introducción al lenguaje del ensamblador. Situaciones especiales del modo V86.

Los ensambladores MASM, TASM y WASM difieren entre sí. Sin embargo, la creación de programas simples para ellos prácticamente no tiene diferencias, con la excepción de la asamblea y el diseño.

Entonces, nuestro primer programa para MASM, TASM y WASM, que muestra la letra inglesa "A" en la posición actual del cursor, es decir, a la izquierda esquina superior Pantalla:

Modelo Tiny .CODE ORG 100H INICIO: MOV AH, 2 MOV DL, 41H INT 21H INT 20H Fin STARTE Este texto se puede escribir en cualquier simple editor de texto - Por ejemplo, en el bloc de notas de Windows (pero no en Word y no en otro "complicado"). Sin embargo, recomiendo el editor de texto "Advanced" con una iluminación de sintaxis, por ejemplo, PSPAD (consulte la sección). Luego, guarde este archivo con extensión.asM, por ejemplo, en la carpeta MyProg. Llamemos al archivo de atest. Entonces, tenemos: C: \\ MyProg \\ Atest.asm.

NOTA
Tenga en cuenta que en el primer equipo grabamos 2 en lugar de 02h. MASM, TAST y WASM, como EMU8086, admiten tal "libertad". Aunque puedes escribir 02h, no habrá errores.

Explicación del programa.:

.Modelo pequeño - 1ª línea. Directive.model define un modelo de memoria para un tipo de archivo específico. En nuestro caso, este es un archivo con la extensión COM, por lo que seleccionamos el modelo pequeño, en el que se combinan los segmentos del código, los datos y la pila. El modelo pequeño está diseñado para crear archivos tipo SOM.

.código. - 2ª línea. Esta directiva comienza el segmento de código.

Org 100h. - 3ª cadena. Este comando establece el valor del contador de software en 100h, porque al cargar el archivo SOM en la memoria, DOS selecciona los primeros 256 bytes al bloque de datos PSP para los primeros 256 bytes (número decimal 256, igual a hexadecimal 100h). El código del programa se encuentra solo después de este bloque. Todos los programas que se compilan en los archivos COM deben comenzar con la presente Directiva.

inicio: MOV AH, 02H - 4ª línea. La etiqueta de inicio se encuentra frente al primer comando en el programa y se utilizará en la directiva final para especificar qué comando comienza el programa. La instrucción MOV coloca el valor del segundo operando en el primer operando. Es decir, el valor de 02H se coloca en el registro de EN. ¿Para qué se hace? 02H es una función DOSOVA que muestra un símbolo en la pantalla. Escribimos un programa para DOS, por lo que usamos los comandos de este sistema operativo (OS). Y escribimos esta función (o más bien su número) está en el Registro de EN, porque la interrupción 21h usa este registro en particular.

Mov dl, 41h - 5ª línea. El código de símbolo "A" se ingresa en el registro DL. El código "A" de acuerdo con el estándar ASCII es el número 41h.

Int 21h. - 6ª línea. Esta es la más interrupción del comando 21h, un comando que causa la función del sistema DOS especificada en el Registro EN de ES (en nuestro ejemplo es una función 02H). El comando int 21h es el principal medio de interacción de los programas del sistema operativo.

Int 20h. - 7ª línea. Esta interrupción que informa el sistema operativo sobre la salida del programa y la transferencia de administración. aplicación de consola. En el caso de que el programa ya esté compilado y ejecutado desde OS, el comando int 20h nos devolverá a OS (por ejemplo, en DOS).

Inicio final. - 8ª línea. La directiva final completa el programa al mismo tiempo que indica qué etiqueta debe ejecutarse.

Int 3.

Llamada interrupción 3 (#BP, punto de parada)

8086

int 3.

CD ib.

En t. imm8.

Interrupciones de desafío imm8.

8086

int 13.

Dentro

Llame a interrupción 4 (#of, desbordamiento) si eflags.of \u003d 1

8086

dentro

Descripción:

Equipo Int 3. Está destinado a generar interrupción 3 y describir la operación idéntica al comando INT N, excepto que el número de interrupción aquí no está presente directamente en el código de operación, pero se establece implícitamente igual a 3.

Esta interrupción está diseñada para su uso por el depurador, que coloca un comando especial de un solo tono. Int 3. (Código CCCH) en lugar del primer byte de comando o en lugar de comandos de una sola vía.

Hay una segunda forma de solicitar esta interrupción utilizando un código de dos bytes INT 3 (código CD03H). pero este método En la práctica, no se aplica, todos los ensambladores X86 son de forma predeterminada por el mnemónico predeterminado Int 3. Como comando de un solo tono con código CCH (pero esto no excluye la posibilidad de programación manual de un byte). Además del tamaño del Código, el proceso de procesamiento de los comandos individuales y de dos bytes es diferente. Int 3.. La interrupción generada por un comando de un solo hombre en modo EV86 (CR4.VME \u003d 1) no está expuesto para redirigir la tarjeta de redirección de interrupción (como se describe para MODE 2, MODE 3, MODE 5) y siempre es procesado por el controlador de modo protegido a través del descriptor en la tabla IDT. Además, en el modo V86, las verificaciones de campo IOPL no se verifican para esta interrupción y, en consecuencia, el error no se puede generar un error #GP cuando EFLAGS.iopl< 3, то есть однобайтная команда не является IOPL-чувствительной .

Operación:

El algoritmo presentado aquí describe no solo el comportamiento del procesador al ejecutar el comando Int 3. Interrupción externa o generación de una situación especial.

Luego ve a. Modo de dirección real;

If (eflags.vm \u003d 1 y eflags.iopl< 3 AND

(Cr4.vme \u003d 0 o cr4.vme \u003d 1 e IRB [N] \u003d 1)

) (* IRB [N] - bit, correspondiente a interrumpir N en el mapa de la redirección de interrupciones *)

#Gp (0); (Interrupción del software INT N en modo: (1) V86 en EFLAGS.IOPL< 3, (2) EV86 Режим 2 *)

DEMÁS. (* Modo protegido o modo V86 / EV86 *)

If (eflags.vm \u003d 1 y cr4.vme \u003d 1 y

(INT N) e IRB [N] \u003d 0)

Otra cosa goto. Modo protegido.; (* Interrupciones de hardware, situaciones especiales; INT N Interrupts: (1) Modo protegido, (2) V86 con EFLAGS.iopl \u003d 3, (3) Modo EV86 1 o 4 *)

MODO REAL-ADDRES:

If ((Número de interrupción * 4) + 3 va más allá del segmento al acceder a la tabla Vectores de interrupción IVT), entonces #GP; Fi;

Si (no hay lugar para 6 bytes en la pila), entonces #SS; Fi;

Eflags.if \u003d 0; (* Restablecer la bandera de interrupciones *)

Eflags.tf \u003d 0; (* Restablecer trampas de bandera *)

Eflags.ac \u003d 0; (* Restablecer la bandera del modo de control de alineación *)

CS \u003d IVT [Número de interrupción * 4] .Selector;

EIP \u003d IVT [Número de interrupción * 4]. FFFSET y 0x0000FFFFH;

(* Continuación del trabajo en direccionamiento real ... *)

EV86-MODO: (* Cr0.pe \u003d 1, eflags.vm \u003d 1, cr4.vme \u003d 1, el modo EV86 es una interrupción del programa INT N, con IRB [N] \u003d 0 - Modo 3 o Modo 5 *)

Si (en la pila de tareas V86 no hay espacio para 6 bytes), entonces #SS (0); Fi;

templags \u003d banderas;

templags.nt \u003d 0;

Luego eflags.if \u003d 0; (* Restablecer la bandera del permiso de las interrupciones *)

templags.if \u003d eflags.vif;

Eflags.vif \u003d 0; (* Restablecimiento de la bandera virtual de interrupciones *)

Eflags.tf \u003d 0; (* Restablecer trampas de bandera *)

PUSH (TEMPFLAGS);

(* Los códigos de error no se ingresan en la pila *)

CS \u003d ivt_v86 [Número de interrupción * 4] .Selector; (* Tabla de vectores de interrupción IVT_V86 se encuentra al principio del espacio de direcciones de la tarea V86 *)

EIP \u003d ivt_v86 [Número de interrupción * 4] .offset y 0x0000ffff; (* El registro EIP de 16 bits más antiguo se restablece *)

(* Trabajo continuo en EV86 ... *)

MODO PROTEGIDO: (* Cr0.pe \u003d 1, interrupciones de hardware, situaciones especiales; INT N Interrupts en modo: (1) Modo protegido, (2) V86 con EFLAGS.IOPL \u003d 3, (3) Modo EV86 1 o Modo 4 *)

Si ((Número de interrupción * 8) + 7 no se encuentra dentro del IDT) Tan #GP (número de interrupción * 8 + 2 + ext); Fi;

(* En lo sucesivo, en los parámetros del código de error, el término +2 significa configurar el código de error del código de error, y los términos + ext - significa configurar el código EXT ERROR de acuerdo con si el error ha causado el programa de interrupción ext \u003d 0 o Externo Ext \u003d 1 *)

AR Descriptor Byte debe establecer la puerta de enlace de interrupción, una puerta de enlace de trampa o una pasarela de la tarea, de lo contrario #GP (número de interrupción * 8 + 2 + ext);

Si (interrupción de software o situación especial) (* Aquellos. Uno de los casos INT N, INT 3, INT01, unido o en *)

If (cpl\u003e dpl gateway)

#Gp (número de interrupción * 8 + 2); (* Cr0.pe \u003d 1, DPL Gateway< CPL, программное прерывание *)

La puerta de enlace debe estar presente, de lo contrario #NP (número de interrupción * 8 + 2 + ext);

If (tareas de pasarela)

Luego ve a. Tarea-Gate.;

Ir. Trampa o int-gate; (* Cr0.pe \u003d 1, interrupción o interrupción de la puerta de enlace *)

Trampa o-int-gate: (* Modo protegido o modo V86 / EV86, trampa o interrupción de la puerta de enlace *)

Comprobación del nuevo selector CS especificado en el descriptor Gateway, y el descriptor apropiado de LDT o GDT:

El selector no debe ser cero, de lo contrario, #GP (EXT);

El índice selector debe caer dentro de la tabla de descriptores, de lo contrario #GP (selector + ext);

El asa seleccionada debe ser un código descriptor de segmento, de lo contrario #GP (selector + ext);

El segmento debe estar presente (P \u003d 1), de lo contrario #NP (selector + ext);

Si (segmento de código no coordinado) y (segmento de código DPL< CPL)

Si eflags.vm \u003d 0

Luego ve a. Int-to-inter-priv; (* Cr0.pe \u003d 1, eflags.vm \u003d 0, interrupción o interrupción de la puerta de enlace, segmento de código inconsistente, segmento de código DPL< CPL *)

Otra cosa (* eflags.vm \u003d 1 *)

Si (DPL del nuevo segmento de código ≠ 0), entonces #GP (segmento de código selector + ext); Fi;

Ir. Int-From-V86-MODE;(* Cr0.pe \u003d 1, eflags.vm \u003d 1, interrupción o interrupción de la puerta de enlace, segmento de código DPL \u003d 0, CPL \u003d 3 *)

DEMÁS. (* Cr0.pe \u003d 1, interrupción o interrupción de la puerta de enlace, segmento de código consistente o segmento de código inconsistente con DPL \u003d CPL *)

Ifflags.vm \u003d 1, entonces #gp (selector de segmento de código + ext); Fi;

If ((correspondiente correspondiente) o (segmento de código DPL \u003d CPL)))

Luego ve a. Int-to-intra -rim; (* Cr0.pe \u003d 1, interrupción o interrupción de la puerta de enlace, segmento de código DPL ≤ CPL para un segmento consistente, segmento de código DPL \u003d CPL para segmento inconsistente *)

Else #gp (selector de segmento de código + ext); (* DPL\u003e CPL para un segmento consistente o DPL ≠ CPL para segmento inconsistente *)

Int-to-inter-priv: (* Modo protegido, interrupción o interrupción de la puerta de enlace, segmento de código inconsistente, segmento de código DPL< CPL *)

Si (TSS actual de 32 bits)

Tssstackaddress \u003d (nuevo segmento de código DPL * 8) + 4

If ((TSSStackAddress + 5)\u003e Límite TSS) (* (Tssstackaddress + 7)\u003e

Noticias \u003d [TSS + TSSSTackAddress + 4] Base; (* 2 bytes cargados *)

(* 4 bytes cargados *)

DEMÁS. (* TSS actual de 16 bits *)

Tssstackaddress \u003d (nuevo segmento de código DPL * 4) + 2

If ((TSSStackAddress + 3)\u003e Límite TSS) (* (Tssstackaddress + 4)\u003e Límite TSS - Para algunos modelos de procesadores *)

Luego #ts (selector del TSS + ext);

Newesp \u003d [TSS + TSSSStackAddress Base]; (* 2 bytes cargados *)

Noticias \u003d [TSS + TSSSTackAddress + 2 Base]; (* 2 bytes cargados *)

El selector de RPL debe ser igual al DPL del nuevo segmento de código, de lo contrario #TS (SS selector + ext);

El DPL del segmento de pila debe ser igual al DPL del nuevo segmento de código, de lo contrario #TS (SS Selector + Ext);

Si (pasarela de 32 bits)

Luego se debe realizar una nueva pila para 20 bytes (24 bytes, si hay un código de error), de lo contrario #SS (ext)

De lo contrario, la nueva pila debe realizarse para 10 bytes (12 bytes, si hay un código de error), de lo contrario #s (ext)

SS: ESP \u003d TSS (Noticias: Newesp); (* Descargar nuevos valores SS y ESP de TSS *)

Si (pasarela de 32 bits)

Luego.

Else CS: IP \u003d PUERTA (selector: offset);

Descargue el descriptor SS en la parte oculta del registro SS;

Si (pasarela de 32 bits)

Empujar (puntero largo a la pila vieja - SS: ESP);

PUSH (puntero largo para devolver el punto - CS: EIP); (* 3 palabras se complementan con 4 *)

PUSH (código de error);

Empujar (puntero largo a la pila vieja - SS: SP); (* 2 palabras *)

PUSH (puntero largo para devolver el punto - CS: IP); (* 2 palabras *)

PUSH (código de error);

CPL \u003d DPL del nuevo segmento de código;

Si (interrupción en la puerta de enlace), entonces eflags.if \u003d 0 fi; (* Restablecer la bandera de interrupción *)

Eflags.rf \u003d 0;

(* Continuación del trabajo en modo protegido a un nivel con grandes privilegios ... *)

Int-From-V86-MODE: (* V86 / EV86 Modo, interrupción o puerta de enlace de captura, DPL \u003d 0, CPL \u003d 3 *)

(* El TSS actual es siempre de 32 bits en modo V86 *)

Si (límite tss< 9) (* Límite TSS< 11 - для некоторых моделей процессоров *)

Luego #ts (selector del TSS + ext);

Noticias \u003d [base TSS + 8]; (* 2 bytes cargados *)

Newesp \u003d [base TSS + 4]; (* 4 bytes cargados *)

Verifique el selector del nuevo segmento de pila de las noticias y el descriptor apropiado de LDT o GDT:

El selector no debe ser cero, de lo contrario #ts (ext);

El índice selector debe caer dentro de la tabla del descriptor, de lo contrario el #TS (SS selector + ext);

El selector de RPL debe ser cero, de lo contrario #TS (SS selector + ext);

El DPL del segmento de pila debe ser cero, de lo contrario, el #TS (SS SELECTOR + EXT);

El descriptor debe tener un formato de descriptor de descriptor de datos permitido para la grabación (w \u003d 1), de lo contrario #TS (SS selector + ext);

El segmento debe estar presente (p \u003d 1), de lo contrario #SS (SS selector + ext);

Si (pasarela de 32 bits)

La nueva pila debe realizarse para 36 bytes (40 bytes, si hay un código de error), de lo contrario #SS (ext)

El nuevo indicador de la instrucción debe caer dentro del nuevo segmento de código, de lo contrario #GP (EXT); (* El puntero de instrucciones está determinado por el valor de campo de compensación del descriptor de la puerta de enlace *)

Tempeflags \u003d eflags;

Eflags.vm \u003d 0; (* El procesador sale del modo V86 para procesar la interrupción en el modo protegido *)

Si (interrupción en la puerta de enlace)

Luego eflags.if \u003d 0;

Cpl \u003d 0; (* Cambie a cero nivel de privilegio *)

SS: ESP \u003d TSS (Noticias: Newesp); (* Descargar valores SS0 y ESP0 de TSS *)

PUSH (GS);

PUSH (FS); (* Se expande a dos palabras *)

PUSH (DS); (* Se expande a dos palabras *)

Empuje (s); (* Se expande a dos palabras *)

Gs \u003d 0; (* Los registros de segmentos se reinician. Es inaceptable el uso posterior de los selectores cero en modo seguro *)

PUSH (TEMPS); (* Se expande a dos palabras *)

PUSH (TEMPEFLAGS);

PUSH (CS); (* Se expande a dos palabras *)

PUSH (código de error); (* Si está presente, 4 bytes *)

CS: EIP \u003d GATE (Selector: offset); (* Selector de descarga: Desplazamiento del descriptor de la puerta de enlace de 32 bits *)

Otra cosa (* Gateway de 16 bits *)

La nueva pila debe tener lugar para 18 bytes (20 bytes, si hay un código de error), de lo contrario #SS (EXT)

(* Ahorro en una pila de registros de 16 bits se produce de manera similar a una puerta de enlace de 32 bits *)

(* Regreso de la interrupción con el comando IRTT al modo V86 desde el segmento V86 desde el segmento de 16 bits, ya que la bandera de VM no se guardará en la pila y no se recuperará de la imagen de EFLAGS al regresar * )

(* Continuación del trabajo en modo protegido en el nivel cero de privilegios ... *)

Int-a-intra-priv: (* Cr0.pe \u003d 1, DPL \u003d CPL o segmento consistente con DPL ≤ CPL *)

Si (pasarela de 32 bits)

Luego, se debe realizar una nueva pila para 12 bytes (16 bytes, si hay un código de error), de lo contrario #s (ext)

De lo contrario, la nueva pila debe realizarse para 6 bytes (8 bytes, si hay un código de error), de lo contrario #SS (EXT)

El nuevo indicador de la instrucción debe caer dentro del nuevo segmento de código, de lo contrario #GP (EXT);

Si (pasarela de 32 bits)

Empujar (puntero largo al punto de retorno); (* 3 palabras se complementan con 4 *)

CS: EIP \u003d GATE (Selector: offset); (* Selector de descarga: Desplazamiento del descriptor de la puerta de enlace de 32 bits *)

PUSH (código de error); (* Si está presente, 4 bytes *)

Empujar (puntero largo al punto de retorno); (* 2 palabras *)

CS: IP \u003d Puerta (selector: offset); (* Selector de descarga: Desplazamiento del descriptor de la puerta de enlace de 16 bits *)

PUSH (código de error); (* Si está presente, 2 bytes *)

Descargue el descriptor CS en la parte oculta del registro CS;

Si (interrupción de la puerta de enlace), eflags.if \u003d 0; Fi;

(* Continuación del trabajo en modo protegido sin cambiar el nivel de privilegio ... *)

Tarea-Gate: (* Cr0.pe \u003d 1, Tarea Gateway *)

Compruebe el selector TSS de la puerta de enlace de tareas Descripción:

El selector debe establecer GDT (BIT TI \u003d 0), de lo contrario #GP (Selector TSS + EXT);

El índice selector debe caer dentro de la tabla GDT, de lo contrario #GP (Selector TSS + EXT);

Comprobación del descriptor TSS correspondiente correspondiente al selector seleccionado:

El descriptor TSS debe tener un tipo de TSS libre (TYPE.B \u003d 0), de lo contrario #GP (Selector TSS + EXT);

Los TSS deben estar presentes (P \u003d 1), de lo contrario #NP (Selector TSS + EXT);

Tareas de conmutación (con adjuntos) en TSS; (* Aquí "con el Anexo" significa el hecho de que al inicializar el contexto de una nueva tarea se establecerá por la bandera EFLAGS.NT \u003d 1, y la tarea SELS SELECTER (OND) se copiará en el segmento TSS (OND) Segmento: consulte Abordaje y Multitarea: Significa soporte multisascia *)

Si (interrupción es una situación especial con código de error)

La pila debe ser un lugar para el código de error, de lo contrario #SS (ext);

PUSH (código de error);

El puntero de instrucciones EIP debe caer dentro del segmento CS, de lo contrario #GP (EXT);

(* Cargar el contexto de una nueva tarea se acompaña de cheques adicionales, como se describe en la sección Dirección y multitarea: medios de soporte de multisadaje *)

(* Continuación del trabajo en el contexto de una nueva tarea ... *)

Situaciones especiales de régimen protegido:

Int 3.Pero también al recibir cualquier interrupción externa o generación de una situación especial. Un poco Ext. En el código de error de la interrupción externa).

  • descriptor vector (índice) de interrupciones no está dentro de la tabla de descriptores de interrupción (IDT);
  • descriptor vector (índice) de la interrupción, no es un descriptor de la puerta de enlace de trampas, una puerta de enlace de interrupción o una pasarela de la tarea;
  • hay una interrupción del software o una situación especial de software (es decir, uno de los casos: INT N, INT 3, INT01, BOTT OR) y al mismo tiempo nivel de privilegio actual (CPL) Tareas más niveles de privilegios(DPL) descriptor de entrada De la tabla IDT -
  • selector de segmentos en el procesado apropiado vector (índice) de interrumpir el descriptor de la puerta de enlace de trampas, la puerta de enlace de interrupción o la puerta de enlace de tareas es un selector de cero;
  • la selección del segmento del segmento de la puerta de enlace de trampas o el descriptor de la puerta de enlace de interrupción no se encuentra dentro de la tabla de descriptores correspondiente;
  • el índice selector de TSS de la interrupción correspondiente del descriptor de la pasarela de tareas no se encuentra dentro de mesa del descriptor global (GDT);
  • descriptor El nuevo segmento de código no es un descriptor de segmento de código;
  • (DPL) Nuevo segmento de código coordinado privilegio de nivel actual (CPL) Tareas -
  • descriptor de nivel de privilegios. (DPL) del nuevo segmento de código inconsistente no es igual nivel de privilegio actual (CPL) Tareas -
  • el selector de TSS de la interrupción correspondiente del descriptor de la pasarela de tareas indica descriptores de mesa locales (LDT);
  • el descriptor TSS de la nueva tarea está marcada como ocupado- TYPE.B ≠ 1.
  • la dirección en la que se debe leer el nuevo valor para puntero de pila (SS: ESP), va más allá del segmento TSS;
  • la selección del nuevo segmento de pila es un selector de cero;
  • el índice selector del segmento de nueva pila no se encuentra dentro de la tabla de descriptores correspondiente;
  • el nivel solicitado de privilegios. (RPL) La selección del nuevo segmento de pila no es igual (DPL) Nuevo segmento de código -
  • descriptor de nivel de privilegios. (DPL) del nuevo segmento de pila no es igual descriptor de nivel de privilegios. (DPL) Nuevo segmento de código -
  • el nuevo segmento de pila no es un segmento de datos disponible para la grabación.
  • el correspondiente interrumpir el descriptor de la puerta de enlace de trampas, la puerta de enlace de interrupción, la pasarela de la tarea o el descriptor TSS está marcado como no acompañado (El descriptor de BIT P se restablece);
  • el nuevo segmento de código no está presente (bit p. El descriptor del segmento se restablece).
  • al escribir en la pila (incluso en una nueva pila, si el conmutamiento de la pila) valora direcciones retorno, puntero de pila, banderas o el código de error es adecuado para el borde permisible del segmento de pila;
  • el nuevo segmento de pila no está presente (el descriptor del segmento de PIT P se restablece).

Situaciones especiales de régimen de direccionamiento real:

La lista de situaciones especiales presentadas aquí caracteriza el comportamiento del procesador no solo cuando se ejecuta el comando Int 3.Pero también al recibir cualquier interrupción externa o generación de una situación especial.

Situaciones especiales del modo V86:

La lista de situaciones especiales presentadas aquí caracteriza el comportamiento del procesador no solo cuando se ejecuta el comando Int 3.Pero también al recibir cualquier interrupción externa o generación de una situación especial. Un poco Ext. En el código de error, se utiliza para indicar externos con respecto al programa de eventos interrumpidos (

Todas las funciones de DOS se llaman al interrumpir 21h (en notación decimal 33). La primera versión de DOS contenía 42 funciones. En la segunda, se agregan 33 funciones más a ellos, que se almacenan en todas las versiones posteriores. La elección de una función específica se lleva a cabo registrando el número correspondiente al Registro AH.

Función 02: Salida simple símbolo en la pantalla

Para emitir un carácter en la pantalla de la PC utilizada

función de interrupción 21H 02:

mov dl,<код выводимого символа>

El símbolo de salida se resalta en la posición del cursor (lo que sea grabado), después de lo cual el cursor se mueve a una posición a la derecha. Si el cursor estaba al final de la cadena de la pantalla, se mueve al principio de la siguiente línea, y si el cursor estaba al final de la última línea de la pantalla, el contenido de la pantalla cambia una línea hacia arriba y los vacíos La cadena aparece en la parte inferior, y el cursor está instalado.

Los símbolos con los códigos 7, 8, 9, 10 (0AH) y 13 (0HDH) se realizan de una manera especial. El símbolo con código 7 (campana, llamada) en la pantalla no se resalta (y el cursor no cambia) y causa señal de sonido. El símbolo con código 8 (retroceso, paso atrás) devuelve el cursor a una posición a la izquierda, a menos que estuviera en la línea izquierda de la cadena. El símbolo con código 9 (pestaña, pestaña) desplaza el cursor a la derecha a la posición más cercana, múltiple 8. El símbolo con código 10 (feed de línea, traducción de línea) Mueve el cursor a la cadena de la siguiente línea, dejándola en la misma. columna. Símbolo con el código 13 (Carrige retorne, el retorno del carro) establece el cursor al principio de la línea actual; Conclusión En una fila de caracteres con códigos 13 y 10 significa traducir un cursor al comienzo de la siguiente línea.

FUNCIÓN 9: Muestra una cadena en la pantalla de visualización

Para mostrar la cadena (secuencias de símbolos), puede, por supuesto, usar la función 02, pero se puede hacer en una recepción utilizando una función de interrupción 21h 09:

DS: DX: \u003d Start Row Dirección

Antes de referirse a esta función, el número del segmento de memoria debe colocarse en el registro DS, en el que se encuentra la línea de salida, y en el registro DX, el desplazamiento de la fila dentro de este segmento. Al mismo tiempo, al final de la línea debe haber un símbolo de $ (código 24h), que sirve como un signo del final de la línea y no se muestra.

Aunque esta característica puede ser mucho más conveniente para las funciones Salida picky en la pantalla (FUNCIÓN 2 Y 6), tiene la desventaja de que se usa un símbolo $ completamente ordinario como un limitador de cadena. Esta es otra compatibilidad del producto lateral con CP / M.

Las funciones avanzadas del sistema operativo DOS como un limitador de cadena usan CHR $ (0). Esto cumple con los acuerdos adoptados en el sistema operativo UNIX y el lenguaje de programación SI.

No existe tal cosa entre las funciones de DOS que muestre números. Tal operación, si es necesario, debe implementarse sobre la base de las funciones consideradas.

Función 4CH: Finalización del programa

Después de completar todas sus acciones, el programa está obligado a devolver la administración del sistema operativo para que el usuario pueda continuar funcionando en la PC. Dicha reembolso se implementa mediante la función de interrupción de 21H, que se coloca al final del programa:

mOV AL,<код завершения>

Cada programa, en general, está obligado a informar, con éxito o no ha completado su trabajo. El hecho es que se llame a cualquier programa de algún otro programa (por ejemplo, del sistema operativo) y, a veces, llamado el programa para continuar correctamente funcionar, debe saber si el programa llamado se ha cumplido, o ha trabajado con un error. Dicha información se transmite como el código de completar el programa (algún entero), que debe ser cero si el programa ha funcionado correctamente, y no cero (que se estipula específicamente en cada caso) de lo contrario. (Puede aprender el código de finalización del programa que se está llamando utilizando la función de interrupción 4DH 21H). Este código será requerido o no, el programa aún debe otorgarlo.

Que es ensamblador

El ensamblador es un lenguaje de programación de bajo nivel. Para cada procesador, hay un ensamblador. Programación en el ensamblador que está trabajando directamente con el instrumento de la computadora. El texto de origen en el lenguaje del ensamblador consiste en comandos (mnemonics), que, después de compilar, se convierten en los códigos de comandos del procesador.

El desarrollo de programas en el ensamblador es algo muy difícil. En lugar del tiempo pasado tiempo, recibe un programa efectivo. Los programas de ensamblaje se escriben cuando cada ciclo del procesador es importante. En el ensamblador, proporciona comandos específicos al procesador y cualquier basura adicional. Esto se logra mediante una alta velocidad de su programa.

Para usar de forma competente el ensamblador, debe conocer el modelo de software del microprocesador. Desde el punto de vista del programador, el sistema de microprocesador consiste en:

  1. Microprocesador
  2. Memoria
  3. Dispositivos de E / S.

El modelo de software está bien descrito en la literatura.

Sintaxis del ensamblador

Formato general de la cadena del programa en el ensamblador

<Метка>: <Оператор> <Операнды> ; <Комментарий>

Etiquetas La etiqueta puede consistir en caracteres y signos de adherencia. Las etiquetas se utilizan en las operaciones de transición condicionales e incondicionales.

Campo del operador. Este campo contiene un equipo Mnemonic. Por ejemplo, Mnemonica mov.

Campo de operandos. Los operandos solo pueden estar presentes si el operador está presente (campo del operador). Los operandos pueden no ser, y tal vez varios. Los operandos pueden ser datos que necesita para realizar algunas acciones (adelante, pliegue, etc.).

Campo de comentarios. El comentario es necesario para el apoyo verbal del programa. Todo lo que está detrás del símbolo. ; Se considera un comentario.

El primer programa en el lenguaje del ensamblador.

Este artículo utilizará un ensamblador para el procesador I80x86 y se utiliza el siguiente software:

  • TASM - Ensamblador turbo Borland - Compilador
  • TLINK - Borland Turbo Linker - Editor de comunicaciones (enlazador)

Para ser concreto, TASM 2.0.

Por tradición, nuestro primer programa retirará la cadena "Hola mundo!" en la pantalla.

Muestra de archivo.Amp.

Modelo pequeño; Memory Model.Stack 100h; Ajuste de la pila de tamaño.data; El inicio del segmento de datos del programa Hellomsg DB "¡Hola mundo!", 13.10, "$". Code; El comienzo del segmento de código AX MOV, @ DATOS; Enviamos la dirección del segmento de datos al Registro MOV DS AX, AX; Instalación del registro DS en el segmento de datos MOV AH; Función de salida de la fila DOS en la pantalla MOV DX, offset Hellomsg; Especificamos el desplazamiento al comienzo de la línea Int 21H; Mostramos la cadena MOV AX, 4C00H; Salida de la función DOS del programa INT 21H; Salida desde el final

Como puede notar que el programa se divide en segmentos: segmento de datos, segmento de código y hay otro segmento de pila.

Considera todo en orden.

Directiva. Modelo pequeño especifica el modelo de memoria. El modelo pequeño es 1 segmento para el código, 1 segmento para datos y pila, es decir, Los datos y la pila están en el mismo segmento. Hay otros modelos de memoria, por ejemplo: pequeños, medios, compactos. Dependiendo del modelo de memoria que elija, los segmentos de su programa pueden superponerse o pueden tener segmentos separados en la memoria.

Directiva.Stack 100h establece el tamaño de la pila. La pila es necesaria para guardar información con su recuperación posterior. En particular, la pila se utiliza durante las interrupciones. En este caso, los contenidos del registro de banderas de las banderas, el registro de CS y el registro IP están apilando. A continuación, hay un programa de interrupción, y luego se restaura por los valores de estos registros.

  • Banderas Banderas El registro contiene señales que se forman después de ejecutar el comando al procesador.
  • El registro CS (segmento de código) contiene la dirección del segmento de código.
  • El registro IP (puntero de instrucciones) es un puntero de comando. Contiene la dirección del comando que debe completarse Siguiente (Dirección relativa al segmento de código CS).

Más descripción detallada Ingresando el marco de un artículo simple.

Directive.data determina el inicio del segmento de datos de su programa. El segmento de datos define "variables", es decir. Hay una redundancia de memoria en los datos requeridos. Después.data va cadena
Hellomsg DB "Hello World!", 13.10, "$"

Aquí Hellomsg es un nombre simbólico que coincide con el inicio de la línea "¡Hola mundo!" (sin comillas). Es decir, esta es la dirección del primer símbolo de nuestra cadena en relación con el segmento de datos. La Directiva de DB (define el byte) define el área de memoria disponible en bypass. 13.10 - Códigos de símbolo Nueva línea Y la devolución del carro, y se requiere el símbolo de $ para el funcionamiento correcto de la función DOS 09H. Entonces, nuestra cadena ocupará en la memoria de 15 bytes.

Directiva. El código determina el inicio del segmento de código (segmento de código CS) del programa. A continuación, las filas del programa que contienen las Mnemónicas de los equipos.

Te contaré sobre el equipo MOV.

mov.<приёмник>, <источник>

Comando MOV - Enviar comando. Ella reenvía los contenidos de la fuente en el receptor. Transferencia puede ser un registro de registro, registro, registro de memoria, pero no hay memoria de memoria de transferencia. Todo pasa a través de los registros del procesador.

Para trabajar con los datos, debe configurar el registro de segmentos de datos. La configuración es que grabamos la dirección de segmento de datos @Data en el registro DS (segmento de datos). Grabar directamente La dirección en este registro no es posible: esta es la arquitectura, por lo que usamos el Registro Axe. En AX, escribimos una dirección de segmento de código.

y luego enviamos los contenidos del Registro Axe al Registro DS.

Después de eso, el registro DS contendrá la dirección del segmento de datos. La dirección DS: 0000H contendrá el símbolo H. Supongo que usted sabe sobre segmentos y compensaciones.

La dirección consta de dos componentes.<Сегмент>:<Смещение>donde el segmento es de 2 bytes y offset - 2 bytes. Resulta 4 bytes para acceder a cualquier lugar de memoria.

mOV AH, 09H
Mov dx, offset hellomsg
Int 21h.

Aquí estamos en el registro AH, escriba el número 09H: el número de la función de interrupción 21, que muestra una cadena en la pantalla.

En la siguiente línea, escribimos la dirección (vergüenza) al comienzo de nuestra línea en el Registro DX.

A continuación, llamamos a la interrupción 21h es la interrupción de las funciones de DOS. Interrumpir: cuando se interrumpe el programa que se está ejecutando y comienza el programa de interrupción. Por número de interrupción, se determina la dirección de la subrutina DOS, que muestra la cadena de caracteres en la pantalla.

Probablemente tendrás una pregunta: ¿Por qué escribimos el número de la función 09h en el registro AH? ¿Y por qué es la compensación de la cadena escrita en el registro DX?
La respuesta es simple: para cada función, se definen registros específicos que contienen datos de entrada para esta función. Consulte qué registros se necesitan funciones específicas que puede en ayuda "e.

mOV AX, 4C00H
Int 21h.

mOV AX, 4C00H: enviamos un número de función al Registro Axe. Función 4C00H - Salir del programa.

iNT 21H - Realizar una interrupción (en realidad salga)

el final es el final del programa.

Después de la directiva final, el compilador lo ignora todo, para que puedas escribir todo, cualquier cosa :)

Si lees hasta el final, entonces eres un héroe!

Maiko g.v. Ensamblador para IBM PC: - M.: "Información comercial", "Sirin" 1999 - 212 p.



¿Te gustó el artículo? Compártelo