LABORATORIO DE PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR x86-16bits

Documentos relacionados
LABORATORIO DE PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR x86-16bits

ENSAMBLADOR DE ARCHIVO TASM MASM NASM GAS. Características de un Ensamblador de Archivo

(3) Unidad 3. Interfaz del ensamblador con el lenguaje C SISTEMAS BASADOS EN MICROPROCESADORES. Grado en Ingeniería Informática EPS - UAM

Estructura de Computadores: Tema 1. Introducción. Índice. Arquitectura del i8086

Tema 1. Fundamentos del lenguaje ensamblador

Tema 4. Fundamentos del ensamblador

Lectura y escritura de un caracter

Examen de Laboratorio de Estructura de Computadores I.T. Informática de Gestión / Sistemas. 16 de junio de 2010 Departamento de Automática ATC

Sobre cómo dividir un programa ensamblador x86 (modo Real) en módulos compilables por separado.

Tema 5: La pila, las macros y los procedimientos

Tema 4. La pila, los procedimientos y las macros

DEBUG Y USO DE CADENAS.

ARQUITECTURA INTERNA DEL µp8086

UNIVERSIDAD TECNOLÓGICA NACIONAL FACULTAD REGIONAL SAN NICOLÁS INGENIERIA EN ELECTRÓNICA

Examen de Laboratorio de Estructura de Computadores Septiembre 2005 I.T. Informática de Sistemas / Gestión Departamento de Automática ATC -

INTRODUCCIÓN AL EMU8086.

Conceptos de Arquitectura de Computadoras Curso 2015

Tema 2: Segmentación y modos de direccionamiento

Pregunta correcta=0,4 Pregunta no contestada=0 Pregunta incorrecta (tipo test)=-0,2

SISTEMAS BASADOS EN MICROPROCESADORES

PROBLEMAS DE ESTRUCTURA DE LOS COMPUTADORES LENGUAJE MÁQUINA Y ENSAMBLADOR

Pregunta correcta=0,4 Pregunta no contestada=0 Pregunta incorrecta (tipo test)=-0,15

Examen de teoría (5 puntos)

SISTEMAS BASADOS EN MICROPROCESADORES

Examen de teoría (5 puntos)

DIRECTIVAS DEL ASM86

Un. VIII. Generación de Código Objeto

5 - Lenguaje Ensamblador

Intel Departamento de Arquitectura 1. Facultad de Ingeniería Universidad de la República. Arquitectura de Computadoras, 2016

Arquitectura Interna del 8088

Examen de teoría (5 puntos)

Examen de teoría (5 puntos)

Funciones y Datos en Intel 8086

PROGRAMACIÓN EN ASSEMBLER SIMULADOR MSX88

8.4. El software en los μprocesadores

(2) Unidad 2. Modelo de Programación del 80x86 de Intel SISTEMAS BASADOS EN MICROPROCESADORES. Grado en Ingeniería Informática EPS - UAM

Tema 5.2: Segmentación y modos de direccionamiento

INSTRUCCIONES. LA ENERGIA DE LA MAQUINA Fundamentos de Computadores Capítulo segundo

Tema 6 Organización y gestión de la memoria

Arquitectura de Computadores II 8086 Parte II

Construyendo Programas más Complejos

Tema 6. Segmentación y modos de direccionamiento

Ensamblador. Introducción. Dpto. Física y Arquitectura de Computadores. Universidad Miguel Hernandez

CONJUNTO DE INSTRUCCIONES µp8086

Tema 4. Lenguaje máquina y lenguaje ensamblador

Es un lenguaje estructurado, tiene una abundante cantidad de operadores y tipos de datos.

Nombre del estudiante: Gustavo Antonio González Morales. Nombre del trabajo: Tarea 2. Investigación sobre Paginación y Segmentacion.

Programación en lenguaje ensamblador. Instrucciones básicas. Formatos. Direccionamientos

Qué es un programa informático?

(4) Unidad 4. Recursos de Programación SISTEMAS BASADOS EN MICROPROCESADORES. Grado en Ingeniería Informática EPS - UAM

Todos los comandos de DEBUG se invocan usando una sola letra y son los siguientes:

Objetivo. Introducción. Tema: GENERACION DE CODIGO. Compiladores, Guía 11 1

Diseño de compiladores. Organización de memoria. Organización de memoria. Organización de memoria. Zona de código 04/05/2014 ORGANIZACIÓN DE MEMORIA

Ejercicios del Tema 3. Fundamentos de la programación en ensamblador

Interrupciones por hardware Interrupciones por so?ware

Procesos y Threads Procesos y Threads. Concurrencia Concurrencia Ventajas Ventajas. Rendimiento Rendimiento (paralelismo) (paralelismo)

Lenguajes de Interfaz

Examen de teoría (5 puntos)

Arquitectura (Procesador familia 80 x 86 )

Tema 5.1: Presentación de datos en pantalla

EL MACROENSAMBLADOR. Objetivos específicos. Materiales y equipo. Procedimiento

Diferentes Perspectivas de un Ordenador

Tema 8 Gestión de la memoria en tiempo de ejecución.

Programación de IA-32 Modo Real

Microprocesadores, Tema 3:

Sistema electrónico digital (binario) que procesa datos siguiendo unas instrucciones almacenadas en su memoria

Ingeniería en Sistemas. Sistemas Operativos. Trabajo Práctico: Repaso de Interrupciones, direccionamiento de memoria y registros del procesador.

Práctica de Estructura de Computadores Sistemas de Entrada/Salida: Entrada/Salida Programada Curso 2010/2011

Tema 5. Formato de instrucciones. Directivas, instrucciones de cadena y programas de varios módulos

Punteros. 1.- Paso de parámetros por referencia. Ya hablamos de ésto en funciones. 2.- Declaración de arreglos dinámicos.

Arquitectura de Computadoras

Tema 8. Directivas y programas complejos

SISTEMAS BASADOS EN MICROPROCESADORES

Práctica 2: Introducción a los modos de direccionamiento

Tema: Lenguaje ensamblador embebido

Organización de Computadoras. Clase 8

INT 21H Función 02H Salida de Carácter LLAMADA: AH = 02H DL = Código ASCII a enviar al dispositivo de salida. DEVUELVE: NADA.

Tema 3 SUBRUTINAS. Estructura de Computadores OCW_2015 Nekane Azkona Estefanía

Cruz García Karen Ilzette González Mendoza María del Rosario Hernández Castañeda Alan Eliseo Sánchez Quiroz Sheila Mariana Varela García Tania

Arquitectura IA-32 Pila. Autor:Alejandro Furfaro

Memoria Estática Punteros, Vectores y Matrices

Todo programa en 'C' consta de una o más funciones, una de las cuales se llama main.

Memoria Estática Punteros, Vectores y Matrices

APUNTES DE LENGUAJE ENSAMBLADOR. Lenguaje ensamblador

62/8&,21(6$/(;$0(1'( /$%25$725,2'((6758&785$6'(/26&20387$'25(6 &8562)(%5(52

Registros de direcciones de 32 bits A0 a A7 (A7 puntero de pila SP)

PRACTICA #1. Aprender a programar una interrupción software empleando C y/o Ensamblador.

Centro Asociado Palma de Mallorca. Tutor: Antonio Rivero Cuesta

ESTRUCTURA Y ORGANIZACIÓN DE COMPUTADORES

Examen de teoría (5 puntos)

Ejercicios del Tema 3. Fundamentos de la programación en ensamblador

Instrucciones de Control de Flujo y Usos de la Pila

RESEÑA DE LENGUAJE C

Sistema Operativo. Repaso de Estructura de Computadores. Componentes Hardware. Elementos Básicos

Universidad Nacional de Ingeniería Arquitectura de Maquinas I. Unidad I: Arquitectura y Programación de un Microprocesador (8086)

Programas Residentes En Lenguaje Ensamblador

ARREGLOS, PUNTEROS Y ASIGNACIÓN DINÁMICA DE MEMORIA

SISTEMAS OPERATIVOS: SISTEMAS DE FICHEROS. Ficheros

Introducción al EMU8086

Transcripción:

LABORATORIO DE PROGRAMACIÓN EN LENGUAJE ENSAMBLADOR x86-16bits De la creación del programa al proceso en ejecución Objetivo El objetivo de esta práctica es conocer y diferenciar los conceptos de programa y proceso. Aprenderemos a desarrollar un programa en ensamblador y qué secciones lo componen. Programa Un programa no es un conjunto de instrucciones solamente. Un programa es un espacio de memoria organizado en secciones bien diferenciadas entre las que no pueden faltar la sección de código, la sección de datos y la sección de pila. El programa compilado se guarda en un fichero que tiene dos partes: el binario y una cabecera con información para el sistema operativo. Las secciones de un programa Un programa requiere de varias secciones de memoria. Evidentemente, una de ellas es la que contiene las instrucciones a ejecutar. Sin embargo, también necesitamos una sección que almacene los datos y una sección para la pila. Las secciones más habituales son: Sección de código La sección de código, sección de texto o simplemente texto, es la que contiene la secuencia de instrucciones a ejecutar. Normalmente es una sección de sólo lectura aunque algunos programas se automodifican o reservan pequeños espacios para datos en esta sección. Esta sección requiere de un puntero especial (puntero de instrucción o contador de programa) que señala la posición de la siguiente instrucción a ejecutar. Sección de datos La sección de datos contiene las variables globales (aquellas accesibles desde todo el programa) y las estáticas (su tiempo de vida abarca todo el tiempo de ejecución del programa) que contienen datos iniciales (inicializadas por el programador). Es una sección de lectura y escritura aunque si una variable se declara como constante se puede alojar en una zona de solo lectura. Sección de bss La sección bss (Block Started by Symbol) contiene variables estáticas no inicializadas, es decir, cuyo valor inicial es 0. Normalmente esta sección no se almacena en el fichero imagen del ejecutable sino que es el cargador del sistema operativo quien realiza la reserva de espacio en memoria principal y el relleno con 0. Sección de heap La sección heap se usa para hacer reservas dinámicas de memoria en tiempo de ejecución. La reserva de un bloque de memoria puede liberarse o incrementarse en tiempo de ejecución. Es una sección que puede crecer y, por tanto, no debe estar limitada por otras secciones. No aparece en el fichero imagen del ejecutable. Sección de pila La sección pila implementa un área de memoria con un tipo de acceso LIFO (Last Input First Output) utilizada en el manejo de procedimientos (subrutinas) que sirve para almacenar temporalmente los argumentos y variables locales. Esta sección requiere de un puntero especial (puntero de pila) que indica la posición de memoria de la cima de la pila. Adicionalmente, se suele utilizar otro puntero especial (puntero de marco de pila) que sirve para referenciar los argumentos y variables locales propios del procedimiento (subrutina) en curso. Es habitual que la sección de pila y la sección de heap crezcan la una contra la otra de manera que, si el programa no ha sido bien diseñado, una sección puede llegar a sobrescribir los datos de la otra.

DE LA CREACIÓN DEL PROGRAMA AL PROCESO EN EJECUCIÓN La cabecera de un programa La cabecera almacena información para el cargador del sistema operativo. Algunos de los datos que proporciona esta cabecera son: tamaño de la cabecera tamaño del fichero binario tabla de direcciones de memoria absolutas máxima y mínima cantidades de memoria requeridas valores iniciales de los punteros de instrucción y de pila Qué es la tabla de direcciones de memoria absolutas? La imagen de un ejecutable se implementa en forma de fichero reubicable, es decir, que ha de funcionar igual sea cual sea el rango de posiciones de memoria principal que se le asignen. Todas aquellas referencias a posiciones de memoria relativas a la posición en curso no tienen problema de ambigüedad. En cambio, todas aquellas referencias absolutas son desconocidas a priori. Por ejemplo, el comienzo de la sección de datos puede ubicarse en cualquier posición de memoria principal y no se conocerá con precisión hasta que el sistema operativo no asigne un mapa de memoria al proceso. Para solucionar este problema, lo que hacemos es referenciar las posiciones absolutas respecto al comienzo de la imagen del ejecutable y confeccionar una tabla con todas las posiciones de memoria absolutas que han de corregirse. Dicha tabla se guarda en la cabecera de la imagen del ejecutable. Una vez que el cargador conoce el rango del mapa de memoria asignado al proceso, modifica todos los valores de las direcciones absolutas de memoria sumando la posición de memoria inicial del proceso con la posición relativa que aparece en la imagen del ejecutable. Veamos un ejemplo. Supongamos que la sección de datos comienza en la posición 1.024B respecto al comienzo de la imagen del ejecutable y supongamos que dicha imagen se va a cargar en la posición de memoria principal 3.456B. En consecuencia, la sección de datos comienza en la posición 3.456B + 1.024B = 4.480B Lo mismo sucede con los punteros de instrucción y de pila. El cargador del sistema operativo calculará los valores efectivos de ambos punteros una vez se conoce el mapa de memoria asignado. Formatos de cabeceras Existen diferentes formatos para las cabeceras de las imágenes de los ejecutables. A continuación se presentan los más importantes: a.out (assembler output): formato original utilizado en entornos UNIX; obsoleto, evolucionó a COFF COFF (Common Object File Format): formato para ejecutables, código objeto y librerías compartidas en entorno UNIX; reemplazado UNIX por ELF sirvió de base para formatos del entorno Windows ELF (Executable & Linkable Format): formato para ejecutables, código objeto, librerías compartidas y volcado de memoria en entorno UNIX; admite una gran variedad de secciones en los ejecutables MZ (Mark Zbikowski): utilizado en el entorno DOS; evolucionó dando lugar a varias extensiones PE (Portable Executable): formato para ejecutables, código objeto, librerías compartidas (DLL), archivos de fuentes y otros usos en entorno Windows; es una evolución de COFF Proceso Un proceso es un programa en ejecución, es decir, una secuencia de instrucciones con una serie de recursos asociados y un estado. Los recursos asociados son el contador de programa, los datos de memoria, la pila y su puntero, los registros y operadores de la ruta de datos y los recursos de E/S (puertos, descriptores de ficheros, etc.). El estado guarda información del punto de ejecución, situación de procesamiento, propietario, privilegios, comunicaciones, mecanismo de devolución del control al sistema operativo, etc. El estado se almacena de diferentes maneras dependiendo de la arquitectura. Creación de un proceso El sistema operativo toma la imagen de un ejecutable, actualiza sus direcciones absolutas e inicializa los datos que lo requieran, copia la imagen actualizada en memoria principal, asigna recursos y transfiere el control a la primera instrucción. 2

LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS Finalización de un proceso Un proceso puede terminar de manera normal devolviendo el control al sistema, puede ser abortado por otro proceso o puede finalizar por error. Estados de un proceso Un proceso puede estar en ejecución, bloqueado (a la espera de algún evento externo) o listo (esperando a disponer de los recursos de ejecución del procesador). Desarrollo de programas en ensamblador x86-16bits Los ficheros ejecutables tienen extensión.exe y se ajustan al formato MZ, es decir, la cabecera del fichero se ajusta a dicho formato MZ. El binario representa todos los segmentos declarados incluyendo la pila. Dependiendo del tipo de declaración, los segmentos pueden estar solapados parcial o totalmente o no estar solapados en absoluto. El tamaño del ejecutable no está limitado a 64KB. El desarrollo de un programa.exe parte de un fichero de código fuente en ensamblador (programa.asm) que se ensambla con masm5.1 dando lugar a un fichero de módulo objeto (programa.obj) que finalmente se enalza (linka) con link generando el fichero ejecutable (programa.exe). programa.asm programa.obj programa.exe MASM programa.asm LINK programa.obj Diseño de secciones en ensamblador x86-16bits El desarrollo de programas con lenguajes de alto nivel confía al compilador el diseño de las secciones de un programa. Por el contrario, el desarrollo de programas en ensamblador x86-16bits permite controlar totalmente este diseño si se considera necesario (definición completa de segmentos) o bien permitir que el programa ensamblador realice ese diseño de una manera transparente al programador (definición simplificada de segmentos). Definición completa de segmentos A continuación se muestra el esqueleto de varios programas que siguen la definición completa de segmentos. Se comenta cada uno de ellos al margen. 3

DE LA CREACIÓN DEL PROGRAMA AL PROCESO EN EJECUCIÓN 1 Definición completa de segmentos Segmentos separados Salida mediante INT 20h ASSUME CS:codigo, DS:datos, SS:pila ; segmento de datos datos SEGMENT datos ENDS ; segmento de pila pila SEGMENT STACK // DECLARACIÓN DEL TAMAÑO DE LA PILA // DB 256 DUP(?) ; pila de 256 bytes pila ENDS main PROC FAR ; dirección de retorno a la pila ; apunta al PSP (DS:0) PUSH DS XOR AX, AX PUSH AX ; inicializamos el segmento de datos MOV AX, DATOS MOV DS, AX ; devolvemos el control al DOS RET main ENDP ; indicamos al programa ensamblador dónde ; comienza el código del programa ; sirve para dar valor a CS:IP END main La primera versión que presentamos es la más antigua por el método de salida (INT 20h). Se declara el comienzo de cada segmento mediante una etiqueta y la directiva SEGMENT. Se declara el final con la misma etiqueta seguida de ENDS. El orden en el que se declaren será el orden en el que aparezcan en la imagen del ejecutable. Siempre tiene que haber un segmento STACK (directiva SEGMENT seguida del operando STACK). En caso contrario el linker emitirá un error. La directiva ASSUME indica qué registro de segmento sirve para direccionar cada segmento. El de código necesariamente debe usar CS. El código fuente finaliza con la directiva END seguida de la etiqueta que marca el comienzo del código. Esto sirve para que CS:IP apunte a la dirección de arranque. En este caso, el código se ha organizado como un procedimiento (main). Cuando se crea el proceso, el sistema operativo salta a la primera instrucción del procedimiento. Lo primero que hace dicho procedimiento es salvar en la pila la dirección de retorno (DS:0). Dicha posición apunta al PSP (área de memoria que guarda el estado del proceso). El PSP comienza con la instrucción INT 20h que devuelve el control al sistema. La segunda tarea que realiza el procedimiento es cargar el registro DS con el valor de comienzo de la sección de DATOS. 2 Definición completa de segmentos Segmentos separados Salida mediante INT 21h servicio 4Ch ASSUME CS:codigo, DS:datos, SS:pila // RESTO DE SEGMENTOS // inicio: MOV AX, DATOS ;inicializamos el MOV DS, AX ;segmento de datos MOV AX, 4C00h ;devolver el control INT 21h ;al MS-DOS END inicio En este caso solamente cambia, respecto al anterior, el modo en el que se devuelve el control al sistema operativo. Ahora se utiliza el servicio 4Ch de la INT 21h prescindiendo del PSP. El segmento de código no adopta forma de procedimiento sino de secuencia de instrucciones. Al igual que en el caso anterior, el código debe comenzar asignando valor al segmento de datos ya que si no se hace, no podrán reverenciarse los datos. 4

LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS 3 Definición completa de segmentos Segmentos solapados Salida mediante INT 21h servicio 4Ch COMUN GROUP codigo, datos, pila ASSUME CS:COMUN, DS:COMUN, SS:COMUN ; segmento de datos datos SEGMENT datos ENDS ; segmento de pila pila SEGMENT STACK DB 256 DUP(?) pila ENDS inicio: MOV AX, COMUN ;inicializamos el MOV DS, AX ;segmento de datos MOV AX, 4C00h ;devolver el control INT 21h ;al MS-DOS END inicio En este caso, los segmentos se solapan totalmente con la intención de que la imagen del ejecutable ocupe menos espacio. La directiva GROUP agrupa varios segmentos lógicos en uno físico bajo un único nombre. La carga del puntero del segmento de datos se realiza bajo el nombre común del grupo (COMUN en este ejemplo). Las referencias a datos se harán anteponiendo a la etiqueta del dato el nombre del grupo. En este caso, COMUN:nombre_dato. 4 Definición completa de segmentos Segmentos solapados Sin segmento de datos (datos en segmento de código) Salida mediante INT 21h servicio 4Ch COMUN GROUP codigo, pila ASSUME CS:COMUN, DS:COMUN, SS:COMUN ; segmento de pila pila SEGMENT STACK DB 256 DUP(?) pila ENDS inicio: JMP ppio ppio: MOV AX, COMUN ;inicializamos el MOV DS, AX ;segmento de datos MOV AX, 4C00h ;devolver el control INT 21h ;al MS-DOS END inicio Con el fin de obtener una imagen de ejecutable aún más compacta, se puede evitar la declaración del segmento de datos. Ahora la reserva de espacio en memoria para los datos se realiza dentro del propio segmento de código. El código comienza con una instrucción de salto incondicional que pasa por encima de la declaración de los datos. 5

DE LA CREACIÓN DEL PROGRAMA AL PROCESO EN EJECUCIÓN Definición simplificada de segmentos La definición simplificada de segmentos deja al programa ensamblador la tarea de diseño de los segmentos. Se invoca con la directiva DOSSEG. Los segmentos se declaran con las directivas.data,.code,.stack (seguido del tamaño), etc. 1 Definición simplificada de segmentos 2 Definición simplificada de segmentos Sin segmento de datos (datos en código) dosseg.model small.stack 100h.data.code inicio: mov ax, @data mov ds, ax mov ah, 4Ch int 21h end inicio dosseg.model small.stack 100h.code inicio: jmp ppio ppio: mov ax, @code mov ds, ax ;ojo, no @data mov ah, 4Ch int 21h end inicio Carga y finalización del proceso bajo MS-DOS Para que el programa se convierta en proceso es necesario que el sistema operativo tome la imagen ejecutable, calcule y escriba las direcciones absolutas (tabla de realocación en el entorno MS-DOS), asigne recursos y transfiera el control al proceso. El estado del proceso de salva en un área de memoria contigua al binario conocida como PSP (Program Segment Prefix). El PSP tiene un tamaño de 256B = 100hB. Como se ha indicado, para cargar los ficheros.exe el sistema operativo debe actualizar las direcciones absolutas anotadas en la tabla de realocación sumando a cada valor de la tabla la dirección de comienzo del proceso. En el momento en el que el sistema transfiere el control del proceso, los punteros adoptan estos valores: DS y ES apuntan al PSP CS e IP toman el valor especificado por la directiva END SS apunta al segmento de pila SP toma el valor del tamaño de la pila Puesto que el sistema operativo asigna a DS y ES el puntero del PSP, es responsabilidad del programador comenzar el código asignando a DS (y ES si se usa) el valor correcto. Para finalizar el proceso, ya hemos visto en los ejemplos de declaración de segmentos, que existen dos mecanismos disponibles: la llamada a la interrupción INT 20h y el servicio 4Ch de la interrupción 21h. cabecera.exe.com PSP cargador programa en memoria rango de memoria libre disponible 6

LABORATORIO DE PROGRAMACIÓN EN ENSAMBLADOR X86-16BITS Prácticas A) Creación de un ejecutable.exe siguiendo la definición completa de segmentos. Queremos crear un ejecutable que contenga la sencilla secuencia de operaciones aritméticas que se propone a continuación: xor ax, ax mov al, operando1 add al, operando2 mov resultado, ax La declaración de datos será la mostrada a continuación. Se declaran tres variables. Dos de tamaño byte para los operandos y una de tamaño word para el resultado. operando1 DB 10h operando2 DB 20h resultado DW 0000h Crea 4 programas que incorporen este código usando los 4 esqueletos propuestos en esta práctica para desarrollar ejecutables usando la definición completa de segmentos. Una vez creados, pásaselos a DEBUG y determina el mapa de memoria de cada uno de ellos. Haz un dibujo y anota la dirección base:desplazamiento donde comienza cada segmento. Toma nota de los valores de los registros de segmento y de IP y SP antes de comenzar la ejecución y después de terminarla. B) Creación de un ejecutable.exe siguiendo la definición simplificada de segmentos. Crea 2 programas usando los esqueletos propuestos en esta práctica para desarrollar ejecutables usando la definición simplificada de segmentos. Utilizando DEBUG, determina el mapa de memoria de cada uno. Haz un dibujo y anota la dirección base:desplazamiento donde comienza cada segmento. Existe alguna diferencia con los mapas de memoria encontrados en el apartado A?. La tarea que vamos a programar es la escritura de un mensaje en la pantalla. Para ello declaramos los datos siguientes: mensaje DB "Hola a todos",13,10 ;Mensaje a escribir longitud EQU $ - mensaje ;No es declaración; es etiqueta de nº entero El código invocará al sistema operativo de la siguiente manera: MOV CX, longitud MOV DX, OFFSET mensaje MOV BX, 1 MOV AH, 40h INT 21h 7