Lenguaje Ensamblador


El lenguaje ensamblador (asm-assembly language) es un lenguaje de programación de bajo nivel.

Este lenguaje es un conjunto de abreviaturas de palabras para sustituir códigos de operación en lenguaje de máquina.

Para aliviar la carga del programador, se desarrollaron códigos mnemónicos de operación y direcciones simbólicas en los comienzos de los años 50’s.

La palabra nemónico se refiere a una ayuda para la memoria. Uno de los primeros pasos para mejorar el proceso de preparación de los programas, era sustituir los símbolos con letras, mnemónicos, por los códigos numéricos de operación del lenguaje de máquina.

Actualmente cada computadora tiene cada una sus códigos mnemónicos, aunque desde luego, los símbolos actuales varían entre fabricantes y modelos.



En este caso el juego completo de instrucciones tiene 200 comandos.

El lenguaje de maquina se va utilizando por la computadora conforme va procesando los datos, pero el software del lenguaje ensamblador primero traduce el símbolo especificado del código de la operación a su equivalente en el lenguaje de máquina.

Un lenguaje hecho en ensamblador se le conoce como programa fuente y un programa convertido a lenguaje de maquina se le llama programa objeto.

El lenguaje ensamblador considerado de bajo nivel,  es una manera de remplazar los “Opcodes” con Mnemónicos.

El lenguaje ensamblador es esencialmente una secuencia de mnemónicos que corresponde a una secuencia de Opcodes, enriquecida con algunas más opciones con el propósito de facilitar la vida de los desarrolladores de programas.

El lenguaje ensamblador no es universal como mencionamos cada fabricante puede tener sus propios códigos según la arquitectura de su CPU.

Para lograr estándares y facilitar la vida de los programadores se hizo un estándar x86 para CPUs de 32 bits y x86-64 para CPUs de 64 bits.

El lenguaje ensamblador es un intérprete para crear código de maquina convirtiendo los mnemónicos en opcodes.

<<Imagen figure >>

La transformación del lenguaje ensamblador en código máquina la realiza un programa ensamblador, y la traducción inversa la puede efectuar un desensamblador. A diferencia de los lenguajes de alto nivel, aquí hay usualmente una correspondencia 1 a 1 entre las instrucciones simples del ensamblador y el lenguaje de máquina.

Sin embargo, en algunos casos, un ensamblador puede proveer "pseudo instrucciones" que se expanden en un código de máquina más extenso a fin de proveer la funcionalidad necesaria y simplificar la programación. Por ejemplo, para un código máquina condicional como "si X mayor o igual que", un ensamblador puede utilizar una pseudo instrucción al grupo "haga si menor que", y "si = 0" sobre el resultado de la condición anterior.

Los Ensambladores más completos también proveen un rico lenguaje de macros que se utiliza para generar código más complejo y secuencias de datos.

Para el mismo procesador y conjunto de instrucciones de CPU, diferentes programas ensambladores pueden tener, cada uno de ellos, variaciones y diferencias en el conjunto de mnemónicos o en la sintaxis de su lenguaje ensamblador.

Por ejemplo, en un lenguaje ensamblador para la arquitectura x86, se puede expresar la instrucción para mover 5 al registro AL de la siguiente manera: MOV AL, 5, mientras que para otro ensamblador para la misma arquitectura se expresaría al revés: MOV 5, AL.

Ambos lenguajes ensambladores harían exactamente lo mismo, solo que está expresado de manera diferente. El primero usa la sintaxis de Intel, mientras que el segundo usa la sintaxis de AT&T.

El uso del ensamblador no resuelve definitivamente el problema de cómo programar un sistema basado en microprocesador de modo sencillo ya que, para hacer un uso eficiente del mismo, hay que conocer a fondo el microprocesador, los registros de trabajo de que dispone, la estructura de la memoria, y muchas cosas más referentes a su estructura básica de funcionamiento.


Ejemplo

Un programa escrito en lenguaje ensamblador consiste en una serie de instrucciones que corresponden al flujo de órdenes ejecutables por un microprocesador.

Por ejemplo, en el lenguaje ensamblador para un procesador x86:

La sentencia

  • MOV AL, 61h

Asigna el valor hexadecimal 61 (97 decimal) al registro "AL".

El programa ensamblador lee la sentencia de arriba y produce su equivalente binario en lenguaje de máquina.

  • Binario: 10110000 01100001(hexadecimal: B61)

El mnemónico MOV es un código de operación u “opcode". El opcode es seguido por una lista de argumentos o parámetros, completando una típica instrucción de ensamblador. En el ejemplo, AL es un registro de 8 bits del procesador, al cual se le asignará el valor hexadecimal 61 especificado.

El código de máquina generado por el ensamblador consiste en 2 bytes. El primer byte contiene empaquetado la instrucción MOV y el código del registro hacia donde se va a mover el dato:

1011  0000  01100001

    |        |        |

    |        |        +---- Número 61h en binario

    |        |      

    |        +--- Registro AL

    +-------- Instrucción MOV

En el segundo byte se especifica el número 61h, escrito en binario como 01100001, que se asignará al registro AL, quedando la sentencia ejecutable como:

  • 10110000 01100001

La cual puede ser entendida y ejecutada directamente por el procesador.


Ejemplo Hello World en lenguaje ensamblador para x86 (bajo el sistema operativo DOS)



; ---------------------------------------------
; Programa que imprime un string en la pantalla
; ---------------------------------------------
.model small              ; modelo de memoria

.stack                    ; segmento del stack

.data                     ; segmento de datos
Cadena1 DB 'Hola Mundo.$' ; string a imprimir (finalizado en $)

.code                     ; segmento del código

; ---------------------------------------------
; Inicio del programa
; ---------------------------------------------
programa:
; ----------------------------------------------------------------------------------------------------
; inicia el segmento de datos
; ----------------------------------------------------------------------------------------------------
MOV AX, @data          ; carga en AX la dirección del segmento de datos
MOV DS, AX             ; mueve la dirección al registro de segmento por medio de AX

; ----------------------------------------------------------------------------------------------------
; Imprime un string en pantalla
; ----------------------------------------------------------------------------------------------------
MOV DX, offset Cadena1 ; mueve a DX la dirección del string a imprimir
MOV AH, 9              ; AH = código para indicar al MS DOS que imprima en la pantalla, el string en DS:DX
INT 21h                ; llamada al MS DOS para ejecutar la función (en este caso especificada en AH)
	
; ----------------------------------------------------------------------------------------------------
; Finaliza el programa
; ----------------------------------------------------------------------------------------------------
INT 20h                ; llamada al MS DOS para finalizar el programa
end programa