UNIDAD 2: PROGRAMACIÓN BÁSICA
2.1 Ensamblador (y
ligador) a utilizar
Así podemos clasificarlos en
Ensambladores Cruzados . Se denominan así los ensambladores que se utilizan en una computadora que posee un procesador diferente al que tendrán las computadoras donde va a ejecutarse el programa objeto producido. Ensambladores Residentes. Son aquellos que permanecen en la memoria principal de la computadora y cargan, para su ejecución, al programa objeto producido.
Este tipo de ensamblador tiene la ventaja de que se puede comprobar inmediatamente el programa sin necesidad de transportarlo de un lugar a otro, como se hacía en cross-assembler, y sin necesidad de programas simuladores. Asimismo, también ocupará memoria el programa fuente y el programa objeto. Son ensambladores que permiten el uso de macroinstrucciones . Debido a su potencia, normalmente son programas robustos que no permanecen en memoria una vez generado el programa objeto.
Puede variar la complejidad de los mismos, dependiendo de las posibilidades de definición y manipulación de las macroinstrucciones, pero normalmente son programas bastantes complejos, por lo que suelen ser ensambladores residentes. El programa que indica al intérprete de instrucciones de la UCP cómo debe actuar se denomina microprograma. El programa que ayuda a realizar esta microprograma se llama microensamblador. Ensambladores de una fase.
Estos ensambladores leen una línea del programa fuente y la traducen directamente para producir una instrucción en lenguaje máquina o la ejecuta si se trata de una pseudoinstrucción. Debido a su forma de traducción, estos ensambladores obligan a definir los símbolos antes de ser empleados para que, cuando aparezca una referencia a un determinado símbolo en una instrucción, se conozca la dirección de dicho símbolo y se pueda traducir de forma correcta. Estos ensambladores son sencillos, baratos y ocupan poco espacio, pero tiene el inconveniente indicado. Ensambladores de dos fases.
Los ensambladores de dos fases se denominan así debido a que realizan la traducción en dos etapas. Estos ensambladores son los más utilizados en la actualidad.
Ensambladores Cruzados . Se denominan así los ensambladores que se utilizan en una computadora que posee un procesador diferente al que tendrán las computadoras donde va a ejecutarse el programa objeto producido. Ensambladores Residentes. Son aquellos que permanecen en la memoria principal de la computadora y cargan, para su ejecución, al programa objeto producido.
Este tipo de ensamblador tiene la ventaja de que se puede comprobar inmediatamente el programa sin necesidad de transportarlo de un lugar a otro, como se hacía en cross-assembler, y sin necesidad de programas simuladores. Asimismo, también ocupará memoria el programa fuente y el programa objeto. Son ensambladores que permiten el uso de macroinstrucciones . Debido a su potencia, normalmente son programas robustos que no permanecen en memoria una vez generado el programa objeto.
Puede variar la complejidad de los mismos, dependiendo de las posibilidades de definición y manipulación de las macroinstrucciones, pero normalmente son programas bastantes complejos, por lo que suelen ser ensambladores residentes. El programa que indica al intérprete de instrucciones de la UCP cómo debe actuar se denomina microprograma. El programa que ayuda a realizar esta microprograma se llama microensamblador. Ensambladores de una fase.
Estos ensambladores leen una línea del programa fuente y la traducen directamente para producir una instrucción en lenguaje máquina o la ejecuta si se trata de una pseudoinstrucción. Debido a su forma de traducción, estos ensambladores obligan a definir los símbolos antes de ser empleados para que, cuando aparezca una referencia a un determinado símbolo en una instrucción, se conozca la dirección de dicho símbolo y se pueda traducir de forma correcta. Estos ensambladores son sencillos, baratos y ocupan poco espacio, pero tiene el inconveniente indicado. Ensambladores de dos fases.
Los ensambladores de dos fases se denominan así debido a que realizan la traducción en dos etapas. Estos ensambladores son los más utilizados en la actualidad.
2.2 Ciclos numéricos
La arquitectura de los procesadores x86 obliga al uso de
segmentos de memoria
para manejar la información, el tamaño de estos segmentos
es de 64kb.
La razón de ser de estos segmentos es que, considerando que
el tamaño máximo
de un número que puede manejar el procesador esta dado por
una palabra de 16
bits o registro, no sería posible accesar a más de 65536
localidades de memoria
utilizando uno solo de estos registros, ahora, si se divide
la memoria de la pc en
grupos o segmentos, cada uno de 65536 localidades, y
utilizamos una dirección
en un registro exclusivo para localizar cada segmento, y
entonces cada dirección
de una casilla específica la formamos con dos registros,
nos es posible accesar a
una cantidad de 4294967296 bytes de memoria, lo cual es, en
la actualidad, más
memoria de la que veremos instalada en una PC.
Para que el ensamblador pueda manejar los datos es
necesario que cada dato o
instrucción se encuentren localizados en el área que
corresponde a sus
respectivos segmentos. El ensamblador accesa a esta
información tomando en
cuenta la localización del segmento, dada por los registros
DS, ES, SS y CS, y
dentro de dicho registro la dirección del dato específico.
2.3 Captura básica de cadenas
2.4 Comparación y prueba
La instrucción CMP pro lo común es utilizada para comparar
dos campos de
datos, uno de los cuales están contenidos en un registro.
El formato general para
CMP es:| [etiqueta:] | CMP | {registro/memoria},
{registro/memoria/inmediato} |
Observe que la operación compara el primer operando con el
segundo; por
ejemplo, el valor del primer operando es mayor que, igual o
menor que el valor del
segundo operando?
La instrucción CMPS compara el contenido de una localidad
de memoria
(direccionada por DS:SI). Dependiendo de la bandera de
dirección, CMPS
incrementa o disminuye también losregistros SI y DI en 1
para bytes, en 2 para
palabras y en 4 para palabras dobles. La operación
establece las banderas AF,
CF, OF, PF, SF y ZF.
Cuando se combinan con un prefijo REP y una longitud en el
CX, de manera
sucesiva CMPS puede comparar cadenas de cualquier longitud.
Pero observe que CMPS proporciona una comparación
alfanumérica, esto es, una
comparación de acuerdo a con los valores ASCII. Considere
la comparación de
dos cadenas que contienen JEAN y JOAN
Algunas derivaciones de CMPS son las siguientes:
· CMPSB. Compara bytes
· CMPSD. Compara palabras dobles
· CMPSW. Compara palabras
2.5 Saltos
La mayoría de los programas constan de varios ciclos en los
que una serie de
pasos se repite hasta alcanzar un requisito específico y
varias pruebas para
determinar qué acción se realiza de entre varias posibles.
Una instrucción usada comúnmente para la transferencia de
control es la
instrucción JMP
(jump, salto, bifurcación). Un salto es incondicional, ya
que la operación transfiere
el control bajo cualquier circunstancia. También JMP vacía
el resultado de la
instrucción previamente procesada; por lo que, un programa
con muchas
operaciones de salto puede perder velocidad de
procesamiento.
La instrucción LOOP, requiere un valor inicial en el
registro CX. En cada iteración,
LOOP de forma automática disminuye 1 de CX. Si el valor en
el CX es cero, el
control pasa a la instrucción que sigue; si el valor en el
CX no es cero, el control
pasa a la dirección del operando. La distancia debe ser un
salto corto, desde -128
hasta +127 bytes. Para una operación que exceda este
límite, el ensamblador
envía un mensaje como "salto relativo fuera de
rango".
2.6 Ciclos condicionales
Sintaxis:
LOOP etiqueta
La instrucción loop decrementa CX en 1, y transfiere el
flujo del programa a la
etiqueta dada como operando si CX es diferente a 1.
Instrucción LOOPE
Propósito: Generar un ciclo en el programa considerando el
estado de ZF
Sintaxis:
LOOPE etiqueta
Esta instrucción decrementa CX en 1. Si CX es diferente a
cero y ZF es igual a 1,
entonces el flujo del programa se transfiere a la etiqueta
indicada como operando.
Instrucción LOOPNE
Propósito: Generar un ciclo en el programa, considerando el
estado de ZF
Sintaxis:
LOOPNE etiqueta
Esta instrucción decrementa en uno a CX y transfiere el
flujo del programa solo si
ZF es diferente a 0.
2.7 Incremento y decremento
Son las instrucciones más básicas a la hora de hacer
operaciones con registros:
INC incrementa el valor de un registro, o de cualquier
posición en memoria, en una
unidad, y DEC lo decrementa.
Instrucción INC
INC AX
Incrementa en uno el valor de AX
IN WORD PTR
Incrementa la palabra situada en CS.
Instrucción DEC
DEC AX
Decremento AX, le resta uno.
DEC WORD PTR
Decrementa la palabra situada en CS.
2.8 Captura de cadenas con formato
Formato de instrucciones para lenguaje ensamblador:
Nombre_procedimiento
PROC
Instrucción operando
destino
, operando fuente
Nombre_procedimiento
ENDP
END
Directivas de segmento
; comentarios
MOV
Transfiere datos entre celdas de memoria y registros.
Sintaxis: MOV Destino,Fuente
Ejemplo:
MOV AX,0006h
MOV DX,AX
MOVS (MOVSB) (MOVSW)
Mueve cadenas de bytes o palabras desde la fuente,
direccionada por SI, hasta el
destino direccionado por DI.
Sintaxis: MOVS
Este comando no necesita parametros ya que toma como
dirección fuente el
contenido del registro SI y como destino el contenido de
DI.
Ejemplo:
MOV SI, OFFSET VARIABLE1
MOV DI, OFFSET VARIABLE2
MOVS
Primero se inicializan los valores de SI y DI con las
direcciones de las variables
VARIABLE1 y VARIABLE2 respectivamente, despues al ejecutar
MOVS se copia
el contenido de VARIABLE1 a VARIABLE2.
Los comandos MOVSB y MOVSW se utilizan de la misma forma
que MOVS, el
primero mueve un byte y el segundo una palabra.
LODS (LODSB) (LODSW)
Carga cadenas de un byte o palabra al acumulador.
Sintaxis: LODS
Toma la cadena que se encuentre en la dirección
especificada por SI, la carga al
registro AL (o AX) y suma o resta 1 (segun el estado de DF)
a SI si la transferencia
es de bytes o 2 si la transferencia es de palabras.
Ejemplo:
MOV SI, OFFSET VARABLE1
LODS
La primer linea carga la dirección de VARIABLE1 en SI y la
segunda linea lleva el
contenido de esa localidad al registro AL.
Los comandos LODSB y LODSW se utilizan de la misma forma,
el primero carga
un byte y el segundo una palabra (utiliza el registro
completo AX).
LAHF
Transfiere al registro AH el contenido de las banderas
Sintaxis: LAHF
Se utiliza para verificar el estado de las banderas durante
la ejecución de un
programa.
Las banderas quedan en el siguiente orden dentro del
registro:
SF ZF __ AF __ PF __ CF
LEA
Carga la dirección del operando fuente.
Sintaxis: LEA destino, fuente
El operando fuente debe estar ubicado en memoria, y se
coloca su
desplazamiento en el registro índice o apuntador
especificado en destino.
Ejemplo:
MOV SI, OFFSET VAR1
Que es equivalente a:
LEA SI, VAR1
POP
Recupera un dato de la pila
Sintaxis: POP destino
Transfiere el último valor almacenado en la pila al
operando destino y despues
incrementa en dos el registro SP.
Este incremento se debe a que la pila va creciendo desde la
dirección mas alta de
memoria del segmento hacia la mas baja, y la pila solo
trabaja con palabras (2
bytes), entonces al incrementar en dos el registro SP
realmente se le esta
restando dos al tamaño real de la pila.
POPF
Extrae las banderas almacenadas en la pila.
Sintaxis: POPF
Transfiere bits de la palabra almacenada en la parte
superior de la pila hacia el
registro de banderas.
La forma de transferencia es la siguiente:
BIT BANDERA 0 CF ___ 2
PF ___ 4 AF ___ 6 ZF 7 SF 8 TF 9 IF 10 DF 11
OF
Estas localizaciones son las mismas para el comando PUSHF
Una vez hecha la transferencia se incrementa en 2 el
registro SP disminuyendo
así el tamaño de la pila.
PUSH
Coloca una palabra en la pila.
Sintaxis: PUSH fuente
La instrucción PUSH decrementa en dos el valor de SP y
luego transfiere el
contenido del operando fuente a la nueva dirección
resultante en el registro recién
modificado.
El decremento en la dirección se debe a que al agregar
valores a la pila ésta crece
de la dirección mayor a la dirección menor del segmento,
por lo tanto al restarle 2
al valor del registro SP lo que hacemos es aumentar el
tamaño de la pila en dos
bytes, que es la única cantidad de información que puede
manejar la pila en cada
entrada y salida de datos.
PUSHF
Coloca el valor de las banderas en la pila
Sintaxis: PUSHF
Decrementa en 2 el valor del registro SP y luego se
transfiere el contenido del
registro de banderas a la pila, en la dirección indicada
por SP.
Las banderas quedan almacenadas en memoria en los mismos
bits indicados en
el comando POPF
2.9 Instrucciones aritméticas
ADC
Adición con acarreo.
Sintaxis: ADC destino, fuente
Lleva a cabo la suma de dos operandos y suma uno al
resultado en caso de que la
bandera CF esté activada, esto es, en caso de que exista
acarreo.
El resultado se guarda en el operando destino.
ADD
Adición de los operandos.
Sintaxis: ADD destino, fuente
Suma los dos operandos y guarda el resultado en el operando
destino.
DIV
División sin signo
Sintaxis: DIV fuente
El divisor puede ser un byte o palabra y es el operando que
se le da a la
instrucción.
Si el divisor es de 8 bits se toma como dividendo el
registro de 16 bits AX y si el
divisor es de 16 bits se tomara como dividendo el registro
par DX:AX, tomando
como palabra alta DX y como baja AX.
Si el divisor fué un byte el cociente se almacena en el
registro AL y el residuo en
AH, si fué una palabra el cociente se guarda en AX y el
residuo en DX.
IDIV
División con signo
Sintaxis: IDIV fuente
Consiste basicamente en lo mismo que la instrucción DIV,
solo que esta última
realiza la operación con signo.
MUL
Multiplicación sin signo
Sintaxis: MUL fuente
El ensamblador asume que el multiplicando sera del mismo
tamaño que el del
multiplicador, por lo tanto multiplica el valor almacenado
en el registro que se le da
como operando por el que se encuentre contenido en AH si el
multiplicador es de
8 bits o por AX si el multiplicador es de 16 bits.
Cuando se realiza una multiplicación con valores de 8 bits
el resultado se
almacena en el registro AX y cuando la multiplicación es
con valores de 16 bits el
resultado se almacena en el registro par DX:AX.
IMUL
Multiplicación de dos enteros con signo.
Sintaxis: IMUL fuente
Este comando hace lo mismo que el anterior, solo que si
toma en cuenta los
signos de las cantidades que se multiplican.
Los resultados se guardan en los mismos registros que en la
instrucción MUL.
SBB
Sbstracción con acarreo
Sintaxis: SBB destino, fuente
Esta instrucción resta los operandos y resta uno al
resultado si CF está activada.
El operando fuente siempre se resta del destino.
Este tipo de substracción se utiliza cuando se trabaja con
cantidades de 32 bits.
SUB
Substracción
Sintaxis: SUB destino, fuente
Resta el operando fuente del destino.
2.10 Manipulación de la pila
-ROT (a b c – c a b) Rota hacia atrás.
-2ROT (ab cd ef – ef ab cd) Rota hacia atrás.
NIP ( a b – b) Quita a de la pila.
OUTK (... n -- ..) Elimina el elemento n.
TUCK (a b -- b a b) Inserta una copia de b.
2?DUP (ab – ab ab) Duplica si ab <> 0.
2DROP (ab -- ) Elimina 2 de encima.
2DUP ( ab – ab ab) Duplica los elementos.
2NIP (ab cd – cd) Elimina elementos.
2OUTK (::: n -- ::) Elimina el elemento n
2OVER (ab cd – ab cd ab) Inserta una copia de ab.
2PICK (:: n -- :::) Copia el elemento n
encima de la pila.
2ROLL (::: n -- :::) Quita el elemento n y
lo deja arriba de la pila.
2ROT (ab cd ef – cd ef ab) Rota los elementos
2TUCK (ab cd – cd ab cd) Inserta una copia de cd.
2SWAP (ab cd – cd ab) Rota los elementos.
2.11 Obtención de cadena con representación
decimal
En este modo, los datos son proporcionados directamente
como parte de la
instrucción.
Ejemplo:
Mov AX,34h ;Copia en AX el número 34h hexadecimal
Mov CX,10 ;Copia en CX el número 10 en decimal
2.12 Instrucciones lógicas
AND
Realiza la conjunción de los operandos bit por bit.
Sintaxis: AND destino, fuente
NEG
Genera el complemento a 2
Sintaxis: NEG destino
Genera el complemento a 2 del operando destino y lo
almacena en este mismo
operando.
Ejemplo, si AX guarda el valor de –2 (FFFE), entonces:
NEG AX
Dejaría como resultado en AX el valor 0002.
NOT
Lleva a cabo la negación bit por bit del operando destino.
Sintaxis: NOT destino
El resultado se guarda en el mismo operando destino.
OR
OR inclusivo lógico
Sintaxis: OR destino, fuente
TEST
Compara logicamente los operandos
Sintaxis: TEST destino, fuente
Realiza una conjunción, bit por bit, de los operandos, pero
a diferencia de AND
esta instrucción no coloca el resultado en el operando
destino, solo tiene efecto
sobre el estado de las banderas.
XOR
OR exclusivo
Sintaxis: XOR destino, fuente
Su función es efectuar bit por bit la disyunción exclusiva
lógica de los dos
operandos.
2.13
Desplazamiento y rotación.
Las instrucciones de desplazamiento son cuatro: shl, shr, sar y
sal; y su objetivo es desplazar los bits de un operando un determinado número
de posiciones a la izquierda o a la derecha. La estructura de los operandos
manejados por estas instrucciones y su significado es idéntico para las cuatro
instrucciones.
·
SHL (Shift Left = desplazamiento a la izquierda)
Se desplazan a la izquierda los bits del operando destino
tantas posiciones como indique el operando fuente. El desplazamiento de una
posición se realiza de la siguiente forma: el bit de mayor peso del operando se
desplaza al bit CF del registro de estado, el resto de los bits se desplazan
una posición hacia la izquierda, y la posición de menor peso se rellena con un
0
·
SAL (Shift Arithmetic Left = desplazamiento
aritmético a la izquierda)
El objetivo de un desplazamiento aritmético a la izquierda
es multiplicar un operando, interpretado con signo, por una potencia de 2.
Para llevar a cabo este tipo de desplazamiento, hay que
desplazar los bits del operando hacia la izquierda introduciendo ceros por su
derecha.
Nota: En realidad, este tipo de
desplazamiento es idéntico al llevado a cabo por la instrucción shl; por tanto,
sal y shl son de hecho la misma instrucción y se codifican con el mismo código
máquina.
· SHR (Shift
Right = desplazamiento a la derecha)
La instrucción shr funciona de la misma forma que shl,
pero desplazando los bits a la derecha en lugar de a la izquierda.
· SAR
(Shift Arithmetic Right = desplazamiento aritmético a la derecha)
Esta instrucción desplaza los bits del operando destino a la derecha tantos bits como indique el operando fuente. Esta forma de funcionamiento es similar a la de la instrucción shr; sin embargo, ambas instrucciones se diferencian en que sar, en vez introducir ceros por la izquierda del operando, replica el bit de mayor peso (bit de signo) en cada desplazamiento.
Esta instrucción desplaza los bits del operando destino a la derecha tantos bits como indique el operando fuente. Esta forma de funcionamiento es similar a la de la instrucción shr; sin embargo, ambas instrucciones se diferencian en que sar, en vez introducir ceros por la izquierda del operando, replica el bit de mayor peso (bit de signo) en cada desplazamiento.
2.14 Obtención de una cadena con la
representación hexadecimal.
Obtención de una cadena con la representación hexadecimal
La conversión entre numeración binaria y hexadecimal es sencilla. Lo primero
que se hace para una conversión de un número binario a hexadecimal es dividirlo
en grupos de 4 bits, empezando de derecha a izquierda. En caso de que el último
grupo (el que quede más a la izquierda) sea menor de 4 bits se rellenan los
faltantes con ceros. Tomando como ejemplo el número binario 101011 lo dividimos
en grupos de 4 bits y nos queda: 10; 1011 Rellenando con ceros el último grupo
(el de la izquierda): 0010; 1011 después tomamos cada grupo como un número
independiente y consideramos su valor en decimal: 0010 = 2; 1011 = 11 Pero como
no podemos representar este número hexadecimal como 211 porqué sería un error,
tenemos que sustituir todos los valores mayores a 9 por su respectiva
representación en hexadecimal, con lo que obtenemos: 2BH (Donde la H representa
la base hexadecimal) Para convertir un número de hexadecimal a binario solo es
necesario invertir estos pasos: se toma el primer dígito hexadecimal y se
convierte a binario, y luego el segundo, y así sucesivamente hasta completar el
número.
La conversión entre numeración binaria y hexadecimal es
sencilla. Lo primero que se hace para una conversión de un número binario a
hexadecimal es dividirlo en grupos de 4 bits, empezando de derecha a izquierda.
En caso de que el último
grupo (el que quede más a la izquierda) sea menor de 4 bits
se rellenan los faltantes con ceros.
2.15 Captura y almacenamiento de datos
numéricos.
Las variables numéricas son muy útiles en ensamblador de la
misma forma que en otros lenguajes de programación, ya que permiten al
programador hacer operaciones aritméticas con datos que se desconocen al
momento de la compilación.
La utilización de datos numéricos es similar a la de
cadenas, con la diferencia de que en vez de declarar las variables como db, se
declaran como dw, lo cual significa que son variables numéricas.
Comentarios
Publicar un comentario