Unidad 1 Introducción al lenguaje ensamblador - JoseCorreaMorales/lenguajes-de-interfaz GitHub Wiki

Unidad 1 - Introducción al lenguaje ensamblador

Tabla de contenidos:

  1. Importancia de la programación en lenguaje ensamblador
  2. El procesador y sus registros internos
  3. La memoria principal (RAM)
  4. El concepto de interrupciones
  5. Llamadas a servicios del sistema
  6. Modos de direccionamiento
  7. Proceso de ensamblado y ligado
  8. Desplegado de mensajes en el monitor

1.1 Importancia de la programación en lenguaje ensamblador

Definición

El lenguaje ensamblador es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de microprocesador

Su importancia

La importancia del lenguaje ensamblador es principalmente que se trabaja directamente con el microprocesador, por lo cual se debe de conocer el funcionamiento interno de este, tiene la ventaja de que en el se puede realizar cualquier tipo de programas que en los lenguajes de alto nivel no lo pueden realizar. Otro punto sería que los programas en ensamblador ocupan menos espacio en memoria.

Algunas ventajas

  • Cercania: Como trabaja directamente con el microprocesador al ejecutar un programa, pues como este lenguaje es el más cercano a la máquina la computadora lo procesa más rápido.

  • Eficiencia de tamaño: Un programa en ensamblador no ocupa mucho espacio en memoria porque no tiene que cargan librerías y demás como son los lenguajes de alto nivel

  • Flexibilidad: Es flexible porque todo lo que puede hacerse con una máquina, puede hacerse en el lenguaje ensamblador de esta máquina; los lenguajes de alto nivel tienen en una u otra forma limitantes para explotar al máximo los recursos de la máquina. O sea que en lenguaje ensamblador se pueden hacer tareas específicas que en un lenguaje de alto nivel no se pueden llevar acabo porque tienen ciertas limitantes que no se lo permite

Algunas desventajas

  • Tiempo de programación:Como es un lenguaje de bajo nivel requiere más instrucciones para realizar el mismo proceso, en comparación con un lenguaje de alto nivel. Por otro lado, requiere de más cuidado por parte del programador, pues es propenso a que los errores de lógica se reflejen más fuertemente en la ejecución.

  • Programas fuente grandes: Por las mismas razones que aumenta el tiempo, crecen los programas fuentes; simplemente requerimos más instrucciones primitivas para describir procesos equivalentes. Esto es una desventaja porque dificulta el mantenimiento de los programas, y nuevamente reduce la productividad de los programadores.

  • Peligro de afectar recursos inesperadamente: Que todo error que podamos cometer, o todo riesgo que podamos tener, podemos afectar los recursos de la máquina, programar en este lenguaje lo más común que pueda pasar es que la máquina se bloquee o se reinicialice. Porque con este lenguaje es perfectamente posible (y sencillo) realizar secuencias de instrucciones inválidas, que normalmente no aparecen al usar un lenguaje de alto nivel.

  • Falta de portabilidad: Porque para cada máquina existe un lenguaje ensamblador; por ello, evidentemente no es una selección apropiada de lenguaje cuando deseamos codificar en una máquina y luego llevar los programas a otros sistemas operativos o modelos de computadoras.

1.2 El procesador y sus registros internos

La CPU

La Unidad Central de Procesamiento (CPU) es el dispositivo f´ısico que ejecuta las instrucciones. Las instrucciones que ejecuta la CPU son por lo general muy simples. Las instrucciones pueden requerir datos que est´en en un lugar especial de almacenamiento de la CPU en s´ı misma llamados registros. La CPU puede acceder a los datos en los registros mucho m´as r´apido que en la memoria. Sin embargo el n´umero de registros en la CPU es limitado, as´ı el programador debe tener cuidado de dejar en los registros s´olo los datos que est´e usando.

Las instrucciones que un tipo de CPU ejecuta las hace en lenguaje de m´aquina. Los programas en lenguaje de m´aquina tienen una estructura mucho m´as b´asica que los lenguajes de alto nivel. Las instrucciones en lenguaje de m´aquina son codificadas como n´umeros, no en formatos de texto amigables. Una CPU debe estar en capacidad de decodificar una instrucci´on muy r´apidamente para ejecutarse eficientemente. EL lenguaje de m´aquina es dise˜nado con este objetivo en mente

Los registros

La CPU tiene 14 registros internos, cada uno de 16 bits. Los primeros cuatro, AX, BX, CX, y DX son registros de uso general y también pueden ser utilizados como registros de 8 bits, para utilizarlos como tales es necesario referirse a ellos como por ejemplo: AH y AL, que son los bytes alto (high) y bajo (low) del registro AX. Esta nomenclatura es aplicable también a los registros BX, CX y DX

Los 14 registros son conocidos por sus nombres específicos:

AX: Acumulador BX: Registro base
CX: Registro contador DX: Registro de datos
DS: Registro del segmento de datos ES: Registro del segmento extra
SS: Registro del segmento de pila CS: Registro del segmento de código
BP: Registro de apuntadores base SP: Registro del apuntador de la pila
SI: Registro índice fuente DI: Registro índice destino
IP: Registro de apuntador de siguiente instrucción F: Registro de banderas

Registros generales o de almacenamiento temporal

AX (registro Acumulador): Este registro es usado, sobre todo, en operaciones aritméticas como primer operando y también como registro de propósito general a disposición del programador.
BX- Registro base: Se utiliza para indicar un desplazamiento (offset)
CX (registro Contador): Este registro se usa siempre que se necesite un contador en operaciones repetitivas y bucles.
DX (registro Dato): Se usa como registro auxiliar en operaciones aritméticas y como contenedor de datos a la hora de usar instrucciones de comunicación de puertos.

Estos cuatro registros, como todos los restantes, son de 16 bits, pero para permitir la realización de operaciones de tipo byte (8 bits) cada uno de estos cuatro registros está dividido en dos subregistros de 8 bits a los que se puede acceder de forma independiente. Así, por ejemplo, los 8 bits inferiores de AX se llaman AL (L de low, bajo) y los 8 superiores AH (H de high, alto). En consecuencia, BX, CX y DX se dividen en BH/BL, CH/CL y DH/DL respectivamente. De esta forma se tiene que todas las instrucciones ensamblador pueden operar con datos de 8 y 16 bits según lo que se precise. En los demás registros esta subdivisión no es posible.

Registros de segmento

Son cuatro registros de 16 bits usados para indicar direcciones de memoria

CS (Code Segment): Este registro es usado por el procesador, junto con el registro IP, para conocer dónde está la instrucción actual que está siendo ejecutada.
DS (Data Segment): Se usa para indicar dónde están todos los datos del programa en ejecución
SS (Stack Segment): En este registro se indica al procesador dónde está la zona de memoria que se usa como segmento de pila.
ES (Extra Segment): Es el registro que referencia al segmento extra, y se usa como apuntador de memoria auxiliar en operaciones complejas donde se necesitan dos punteros de datos simultáneos.

Registros de pila

La pila es un área de memoria importante. Tiene, en vez de uno, dos registros que se usan como desplazamiento (offset) para apuntar su contenido. Se usan como complemento al registro SS y son:

SP (Stack Pointer): Es el registro que se reserva el procesador para uso propio en instrucciones de manipulación de la pila.
BP (Base Pointer): Se usa como registro auxiliar

Registros indices

Se utilizan como desplazamientos complementarios para DS y ES a la hora de indicar la posición donde se encuentran los datos a los que se desea acceder. Son lo siguiente:

SI (Source index): Se usa como puntero origen en operaciones de desplazamiento de datos entre dos zonas de memoria
DI (Destination index): Se usa como destino en operaciones de desplazamiento de datos

1.3 La memoria principal (RAM)

(RAM, random access memory). En este contexto, el término aleatorio significa que puede accederse a cualquier celda de memoria en el mismo tiempo, independientemente de su posición en la estructura de la memoria.

SRAM

Los circuitos de memoria de acceso aleatorio basados en flip flops, , se conocen como circuitos de memoria estática (SRAM, static RAM), debido a que el contenido de cada posición de la memoria se mantiene en tanto se mantenga la alimentación eléctrica del circuito integrado.

DRAM

Los circuitos integrados de memoria dinámica, llamados DRAM, utilizan un capacitor que almacena una pequeña cantidad de carga eléctrica, y en el cual el nivel de carga representa un 0 o un 1. Los capacitores son mucho más chicos en tamaño que los flip flops y, por consiguiente, un circuito integrado de memoria dinámica basada en capacitores puede almacenar en la misma superficie una cantidad de información mucho mayor que una memoria estática. Dado que las cargas de los capacitores se van disipando en el tiempo, las memorias dinámicas requieren que la carga de sus celdas sea restalbecida o refrescada en forma periodica y con frecuencia.

1.4 El concepto de interrupciones

Algunas veces el flujo ordinario de un programa debe ser interrumpido para procesar eventos que requieren una respuesta rápida. El hardware de un computador provee un mecanismo llamado interrupción para manipular estos eventos. Por ejemplo cuando se mueve el ratón la interrupción de hardware del ratón es el programa actual para manejar el movimiento del ratón (para mover el cursor del mouse, etc) Las interrupciones hacen que el control se pase a un manipulador de interrupciones. Los manipuladores de interrupciones son rutinas que procesan la interrupción. A cada tipo de interrupción se le asigna un número entero. En el comienzo de la memoria física una tabla de vectores de interrupción que contiene la dirección del segmento de los manipuladores de la interrupción. El número de la interrupción es escencialmente un índice en esta tabla.

Interrupciones por software: Son aquellas programadas por el usuario, es decir, el usuario decide cuando y donde ejecutarlas, generalmente son usadas para realizar entrada y salida

Interrupciones por hardware: Son aquellas que son provocadas por dispositivos externos al procesador su característica principal es que no son programadas, esto es, pueden ocurrir en cualquier momento en el programa. Existen dos clases de interrupciones de este tipo:

  • Interrupciones por hardware enmascarables: Aquellas en las que el usuario decide si quiere o no ser interrumpido.
  • Interrupciones por hardware no enmascarables (NMI): Aquellas que siempre interrumpen al programa.

1.5 Llamadas a servicios del sistema

llamada al sistema (en inglés system call) es el mecanismo usado por una aplicación para solicitar un servicio al sistema operativo.

  • Llamadas al sistema no bloqueantes: son aquellas llamadas en las que, si lo que se solicita no está disponible, el proceso no se queda bloqueado, sino que devuelven un valor especial indicando la condición de información no disponible

  • Llamadas al sistema bloqueantes: la aplicación se bloquea a la espera del resultado. Si un hilo hace una llamada bloqueante, todos los hilos se bloquearán. Si hace una llamada no bloqueante, los demás hilos podrán seguir ejecutando.

Tipos de llamadas al sistema
Control de procecesos: Terminar (end), abortar (abort), cargar (load), ejecutar (execute), crear procesos (create process, terminar procesos (terminate process), inicia un nuevo proceso (fork), esperar para obtener tiempo (wait time), etc
Administración de archivos: crear archivos (create), borrar archivos (delete), abrir (open), cerrar (close), leer (read), escribir (write), etc
Adminsitración de dispositivos: Solicitar dispositivo (request), Liberar dispositivo (release), Leer (read), Escribir (write), Reposicionar (reposition), etc
Mantenimiento de la información: obtener la hora (time), la fecha (date), etc

1.6 Modos de direccionamiento

Los modos de direccionamiento en computadoras son formas de especificar la ubicación de un dato o instrucción en la memoria de una computadora. Algunos modos de direccionamiento comunes son:

  • Direccionamiento Absoluto: El valor de la dirección es específico y no depende de la posición actual del programa o del procesador.

  • Direccionamiento Relativo: La dirección se especifica en términos de la posición actual del programa o del procesador.

  • Direccionamiento Indirecto: La dirección real se especifica a través de otra dirección en la memoria.

  • Direccionamiento Por Registro: La dirección se almacena en un registro en lugar de en la memoria.

  • Direccionamiento Por Desplazamiento: La dirección se especifica en términos de una dirección base y un desplazamiento.

Cada modo de direccionamiento tiene sus propias ventajas y desventajas, y su elección depende del diseño y objetivos específicos de la computadora y del sistema operativo que se está utilizando.

1.7 Proceso de ensamblado y ligado

El proceso de ensamblado y enlazado en lenguaje ensamblador es un proceso que convierte el código escrito en lenguaje de ensamblador en un programa ejecutable que puede ser corrido por la computadora. El proceso consta de dos etapas principales: el ensamblado y el enlazado.

  1. Ensamblado: Es el proceso de traducir el código fuente escrito en lenguaje de ensamblador a código objeto. Durante el ensamblado, se reemplazan las instrucciones mnemónicas del lenguaje de ensamblador con las representaciones numéricas correspondientes en la CPU y se resuelven las referencias a las direcciones de memoria.

  2. Enlazado (Ligado): Es el proceso de combinar varios archivos objeto en un solo programa ejecutable. Durante el enlazado, se resuelven las referencias a las funciones y datos externos que se encuentran en otros archivos objeto y se combinan todos los archivos en un único archivo ejecutable.

El proceso de ensamblado y enlazado es importante porque permite a los programadores escribir programas complejos que se dividen en módulos más pequeños y manejables, y mejora la eficiencia al permitir que varios programas compartan código y datos.

1.8 Desplegado de mensajes en el monitor

El despliegue de mensajes en un monitor en lenguaje ensamblador implica escribir texto en la memoria y configurar el controlador de video para que muestre el texto en la pantalla.

Para desplegar un mensaje en un monitor, es necesario conocer la estructura de la memoria de vídeo y cómo acceder a ella. En ensamblador x86, esto se hace a través de registros y direcciones de memoria específicas.

Para desplegar texto en pantalla en ensamblador, generalmente se requiere hacer lo siguiente:

  1. Establecer una dirección de memoria donde almacenar el texto.
  2. Escribir cada carácter en la memoria.
  3. Configurar el controlador de video para que apunte a la dirección de memoria y muestre el texto en pantalla.

Ejemplo

section	.text
	global _start       ;must be declared for using gcc
_start:                     ;tell linker entry point
	mov	edx, len    ;message length
	mov	ecx, msg    ;message to write
	mov	ebx, 1	    ;file descriptor (stdout)
	mov	eax, 4	    ;system call number (sys_write)
	int	0x80        ;call kernel
	mov	eax, 1	    ;system call number (sys_exit)
	int	0x80        ;call kernel

section	.data

msg	db	'Hello, world!',0xa	;our dear string
len	equ	$ - msg			;length of our dear string