Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Prembulo
1. Generalidades
1.1. Sistemas numricos 1.1.1. Sistema decimal 1.1.2. Sistema binario 1.1.3. Conversin
entre decimal y binario 1.1.4. Operaciones matemticas bsicas en base dos 1.1.5.
Operaciones lgicas 1.1.6. El sistema hexadecimal 1.1.6.1. Conversin entre hexadecimal y
decimal 1.1.6.2. Conversin entre hexadecimal y binario 1.1.7. Representacin de datos
1.1.7.1. Bit 1.1.7.2. Nibble 1.1.7.3. Byte 1.1.7.4. Palabra 1.1.7.5. Palabra doble 1.1.7.6.
Cudruple palabra 1.1.7.7. Mltiplos del byte 1.1.7.8. Nmeros con y sin signo 1.1.7.9.
Nmeros reales 1.1.7.9.1. Inexactitudes en la representacin de los nmeros reales en
binario 1.1.7.10. Little Endian vs Big Endian 1.2. Registros 1.2.1. Registros de propsito
general 1.2.2. Registros de segmento 1.2.3. Registros punteros de pila 1.2.4. Registros
ndices 1.2.5. Puntero de instrucciones o contador de programa 1.2.6. Registro de estado o
de indicadores (flags) 1.2.7 Resumen grfico del conjunto de registros del 8086: 1.2.7.1.
Registros de propsito general 1.2.7.2. Registros Punteros de Pila 1.2.7.3. Registro Puntero
de Instrucciones 1.2.7.4. Registros de Segmento 1.2.7.5. Registros de ndice 1.2.7.6.
Registro de banderas 1.3. Puertos de entrada/salida 1.4. Organizacin de direcciones:
Segmentacin 1.4.1. Modos de direccionamiento 1.4.2. Tipos de direccionamiento 1.4.3. La
pila 1.4.4. Memoria Interna 1.4.5. Memoria Convencional 1.4.6. Segmentos de Ensamblador
1.4.6.1. Alineacin 1.4.6.2. Combinacin 1.4.6.3. Clase 1.4.6.4. Acceder a datos de
Segmento 1.4.6.5. Tipos de Modelos de Memoria 1.4.6.6. Smbolos Predefinidos 1.5.
Programas ejecutables sobre MS-DOS 1.5.1. El PSP 1.5.2. Programas COM 1.5.2.1. Creacin
de un programa COM en ensamblador 1.5.3. Programas EXE 1.6. Diferencias entre las
sintaxis 1.6.1. Diferencias entre NASM y MASM 1.6.1. Diferencias entre NASM y FASM
2. Hola Mundo
2.1. Hola, Mundo!- COM 2.1.1. Sintaxis MASM 2.1.1.1. MundoCM1.asm 2.1.1.2.
MundCM1b.asm 2.1.1.3. MundoCM2.asm 2.1.1.4. MundoCM3.asm 2.1.1.5. MundoCM5.asm
2.1.2. Sintaxis NASM 2.1.2. Sintaxis FASM 2.2. Hola, Mundo!- EXE 2.2.1. Sintaxis MASM
2.2.1.1. MundoXM1.asm 2.2.1.2. SegGrpM1.asm 2.2.1.3. SegtosM1.asm 2.2.2. Sintaxis
NASM 2.2.2.1. MundoXN1.asm 2.2.2.2. SegGrpN1.asm 2.2.2.3. SegtosN1.asm 2.2.3. Sintaxis
FASM 2.2.3.1. MundoXF1.asm 2.2.3.2. SegtosF1.asm
3. Datos
3.1. Datos Simples 3.1.1.Constantes 3.1.2.Caracteres 3.1.3.Enteros Pequeos - Bytes
3.1.4.Enteros - Word 3.1.5.Enteros Dobles - Double Word 3.1.6.Enteros Largos QWord
3.1.7.Enteros Extendidos TWord 3.1.8.Reales Simples 3.1.9.Reales Largos 3.1.10.Reales
Extendidos 3.1.11.Cadenas de Caracteres 3.1.12. Matrices 3.2. Datos Complejos 3.2.1. Tipos
3.2.2. Punteros 3.2.2.1. Punteros a punteros 3.2.2.2. Punteros a matrices 3.2.2.3. Punteros a
estructuras 3.2.2.4. Matrices de punteros 3.2.2.5. Estructuras de punteros 3.2.3. Estructuras
3.2.3.1. Alineacin 3.2.3.2. Punteros a Estructuras 3.2.3.3. Estructuras de Punteros 3.2.3.4.
Matrices de Estructuras 3.2.3.5. Estructuras Anidadas 3.2.4. Uniones 3.2.5. Campos de Bits
(Records) 3.3.Ejercicios
4. Control de flujo
4.1. Saltos 4.1.1. Direcciones Corta, Cercana y Lejana 4.1.2. Etiquetas 4.1.2.1.mbito de las
etiquetas 4.1.2.1.Etiquetas annimas 4.1.2. Saltos incondicionales 4.1.3.1. Saltos Cortos
4.1.3.2. Saltos Cercanos 4.1.3.1. Saltos Lejanos 4.1.4. Instrucciones de testeo 4.1.4.1.La
bandera de acarreo (CF) 4.1.4.2.La bandera de paridad (PF) 4.1.4.3.La bandera auxiliar (AF)
4.1.4.4.La bandera de cero (ZF) 4.1.4.5.La bandera de signo (SF) 4.1.4.6.La bandera de
trazado (TF) 4.1.4.7.La bandera de interrupciones (IF) 4.1.4.8.La bandera de direccin (DF)
8.1.8.1. El color 8.1.8.2. Ejemplos 8.1.9. Ejemplos completos en modo texto 8.1.9.1. Copper
bars 8.1.9.2. Foco 8.1.9.3. Caleidoscopio 8.1.9.4. Tetris 8.1.9.5. Depuracin
9. El teclado
9.1. El teclado 9.1.1. Distribucin del teclado 9.1.2. rea de datos del teclado 9.1.3. El bfer
del teclado 9.1.4. Cdigos scan 9.1.5. Interrupcin 21h DOS para el teclado 9.1.5.1. Funcin
1 9.1.5.2. Funcin 6 9.1.5.3. Funcin 7 9.1.5.4. Funcin 8 9.1.5.5. Funcin 0Ah 9.1.5.6.
Funcin 0Bh 9.1.5.7. Funcin 0Ch 9.1.6. Interrupcin 16h BIOS para el teclado 9.1.6.1.
Funcin 0 9.1.6.2. Funcin 1 9.1.6.3. Funcin 2 9.1.6.4. Funcin 3h 9.1.6.4. Funcin 10h
9.1.6.5. Funcin 11h 9.1.6.6. Funcin 12h
10. Ficheros
10.1. Gestin de Ficheros 10.1.1. Estructura fsica del disco 10.1.1.1. rea de Sistema
10.1.1.2. rea de datos 10.1.2. Operaciones de la BIOS para disco 10.1.2.1. Byte de estado
de la BIOS 10.1.3. Operaciones MS-DOS para disco con FCBs 10.1.4. Operaciones MS-DOS
para disco con handles 10.1.4.1. Manejadores de archivos 10.1.4.2. Atributos de archivo
10.1.4.3. Formato de fecha y hora de los archivos 10.1.4.4. Cdigos de error en acceso a
disco 10.1.4.5. Funciones Handle de acceso a disco 10.1.5. Bsqueda de ficheros con MSDOS 10.1.5.1. Estructura de la DTA 10.1.5.2. Funciones de bsqueda de ficheros 10.1.6.
Funciones avanzadas MS-DOS para disco 10.1.7. Los buffers de archivo 10.2. Mtodos de
acceso a los archivos 10.2.1. Acceso secuencial a archivos 10.2.1.1. Creacin y escritura de
archivos 10.2.1.2. Apertura y cierre de archivos 10.2.1.3. Lectura y escritura de datos
10.2.1.4. EOF (End Of File o fin de fichero) 10.2.1.5. Seek (buscar) 10.2.2. Acceso aleatorio a
archivos 10.2.2.1. Escritura de un archivo aleatorio 10.2.2.2. Lectura de un archivo aleatorio
10.2.3. Acceso binario a archivos 10.2.3.1. Escritura de un archivo binario 10.2.3.2. Lectura
de un archivo binario 10.2.4. Otros procesos sobre archivos 10.2.4.1. Borrar ficheros
10.2.4.2. Buscar ficheros 10.2.4.3. Volcar el contenido de un fichero a la pantalla
11. Interrupciones
11.1. Interrupciones 11.1.1. Polling versus Interrupciones 11.1.1.1. Polling 11.1.1.2.
Interrupciones 11.1.1.3. Conclusin 11.1.2. Interrupciones internas o excepciones 11.1.3.
Interrupciones hardware (IRQs) 11.1.4. Interrupciones software 11.1.4.1. Localizacin
11.1.4.2. Ejemplo / traceo 11.1.4.3. Proceso de la interrupcin 11.1.5.Tabla de interrupciones
del sistema 11.1.6. ISRs 11.1.6.1. Preservar contenido de registros 11.1.6.2. Deshabilitar
ejecucin de interrupciones 11.1.6.3. Reservar suficiente espacio de pila 11.1.7. Gestin de
interrupciones 11.1.7.1. Interrupciones para gestin de interrupciones 11.1.7.2. Mtodos
para la gestin de interrupciones 11.1.8. Ejemplos 11.1.8.1. Int 4h 11.1.8.2. Int 21h
11.1.8.3. Int 9h 11.1.8.4. Int 8h 11.1.8.5. Reloj en tiempo real 11.1.8.6. Muestra teclado
11.1.8.7. Hora y fecha actuales 11.1.8.8. Establece rutina propia para interrupcin 11.1.8.9.
Buscar Interrupcin 11.1.9. Interrupcin Multiplex
12. Gestin de la memoria
12.1. Gestin de Memoria 12.1.1. Mapa de la memoria del MS-DOS 12.1.1.1. Tipos de
memoria 12.1.1.1.1. Memoria convencional 12.1.1.1.2. rea de Memoria Superior (Upper
Memory Area UMA) 12.1.1.1.2. Mapa de la Memoria Superior 12.1.1.1.3. Memoria Superior
ROM y RAM 12.1.1.1.4. Memoria Expandida (Expanded Memory EMS) 12.1.1.1.5. Bloques
de Memoria Superior (UMBs) 12.1.1.1.6. ROM Shadowing 12.1.1.1.7. Area de Memoria Alta
(High Memory Area HMA) 12.1.1.1.8. Memoria Extendida 12.1.1.1.9. Memoria Cach
12.1.1.1.10. Memoria CMOS RAM 12.1.2. Bloques de memoria 12.1.2.1. Tipos de bloques de
memoria 12.1.2.1.1. Bloques de memoria del programa 12.1.2.1.2. Bloques de entorno
12.1.2.1.3. Bloques de control de memoria (MCB's) 12.1.2.1.4. Bloques de sistema
12.1.2.1.5. Bloques de datos 12.1.2.1.6. Bloque libre 12.1.2.2. Liberar el espacio de entorno
en programas residentes 12.1.2.3. Redimensionamiento de un bloque de memoria 12.1.2.4.
16.1. Joystick 16.1.1. Breve historia del Joystick 16.1.2. Estructura del Joystick 16.1.3.
Conector del Joystick 16.1.4. Cmo trabaja el hardware del puerto del joystick 16.1.4.1.
Entrada analgica de resistencia (posicin del joystick) 16.1.4.2. Entrada de conmutadores
(botones del joystick) 16.1.5. Cmo programar el joystick analgico 16.1.5.1. Funciones
BIOS 16.1.5.2. Lectura directa del puerto de juegos
17. Control del tiempo
17.1. El tiempo 17.1.1. Usando interrupciones 17.1.2. Accediendo a la informacin de la
BIOS directamente 17.1.3. Interceptando la interrupcin 1Ch o 8h 17.1.4. Usando el refresco
de pantalla 17.1.5. Multiretardo 17.1.6. Programacin del PIT 17.1.6.1. Canales del PIT
17.1.6.1.1. El canal 0 17.1.6.1.2. El canal 1 17.1.6.1.3. El canal 2 17.1.6.2. El registro de
modo/comando en el puerto 43h 17.1.6.3. Cmo programar el canal 0 a una frecuencia
diferente 17.1.6.4. Riesgos a tener en cuenta 17.1.6.5. Otra forma de usar el PIT
18. El sonido en el PC
18.1. El altavoz del PC 18.1.1. El sonido 18.1.1.1. Problemas del sonido 18.1.1.2. Ejemplo
18.1.2. El sonido sobre el PC 18.1.3. Funcionamiento del altavoz del PC 18.1.3.1. Control
directo del altavoz 18.1.3.2. Control del altavoz mediante el temporizador 18.1.4. Notas
musicales 18.1.5. Melodas 18.1.6. Melodas de fondo 18.1.7. Msica digital por el altavoz
18.1.7.1. Ficheros de sonido digital 18.1.7.2. Formato de fichero wav 18.1.7.3. Otros
formatos de sonido digital 18.1.7.3.1. Formato MOD 18.1.7.3.2. Formato S3M 18.1.7.3.3.
Formato XM 18.1.7.3.4. Formato MID y MID+Audio 18.1.7.4. Programas para la creacin de
canciones y formatos musicales 18.1.7.4.1. Trackers 18.1.7.4.2. Secuenciadores 18.1.7.4.3.
Trackers de ejemplo 18.2. Sound Blaster
19. Interfaces con lenguajes de alto nivel (HLL)
19.1. Interfaces del ensamblador 19.1.1. Elementos que intervienen en la interfaz 19.1.2. La
interfaz 19.1.2.1. El control del flujo 19.1.2.2. El acceso a los datos 19.1.3. Seguridad 19.2.
Subrutinas y enlace 19.2.1. Linkado 19.2.1.1. PUBLIC nombre 19.2.1.2. EXTRN nombre: tipo
19.2.2. Fin del mdulo principal 19.2.3. Ensamblado y linkado 19.3. Interfaz con Pascal
19.3.1. Tipos de Interfaz con Turbo Pascal 19.3.1.1. Interfaz interna 19.3.1.1.1. Parmetros
en los procedimientos 19.3.1.1.2. Ejemplos 19.3.1.2. Interfaz externa 19.3.1.2.1. Ejemplos
19.3.2. Virtual Pascal y Free Pascal 19.4. Interfaz con C 19.4.1. Comunicacin entre C y
ensamblador 19.4.2. Ejemplos 19.4.3. Pelles C 19.4.3.1. Ejemplos 19.4.3. Tiny C 19.4.3.1.
Ejemplos 19.5 Interfaz con Basic 19.5.1. Ejemplos 19.5.1.1. Interfaz interna 19.5.1.2.
Interfaz externa 19.5.1.3. Creacin de Quick Libraries 19.5.2. Visual Basic y Rapid QBasic
19.6. Mdulos en ensamblador 19.6. Depurar
20. Programacin Windows
20.1. Programacin Windows 20.1.1. Antes de empezar 20.1.1.1. Definiciones bsicas
20.1.1.1.1. La pila (registro SS) 20.1.1.1.2. Los registros de bandera 20.1.1.2. Cuentas
previas 20.1.1.3. Instalacin de paquetes 20.1.1.4. RADs para ensamblador 20.1.1.5.
Inclusin de definiciones y bibliotecas 20.1.1.6. Los programas que vamos a ver 20.1.2.
Programas de consola Windows 20.1.3. Primer programa Windows con ventanas 20.1.4.
Primera ventana Windows 20.1.4.1. Ventana simple Windows 20.1.4.2. Ventana con resource
externo Windows 20.1.4.3. Ventana con resource interno Windows 20.1.5. Texto en la
ventana Windows 20.1.5.1. Texto con DrawText 20.1.5.2. Texto con CreateWindowEx,
posicin libre 20.1.5.3. Texto customizado 20.1.5.4. Texto con gdi 20.1.5.5. Texto con
resources 20.1.5.6. Hiperenlace con resources externos 20.1.6.6. Hiperenlace con resources
internos 20.1.7. Dibujo en la ventana Windows 20.1.7.1. Caleidoscopio con gdi y
WinMain.msg_loop 20.1.7.2. Caleidoscopio con gdi y WndProc.TIMER 20.1.7.3. Ejemplo de
grficos con gdi 20.1.7.4. Ejemplo de grficos con gdi 20.1.7.5. BMP con resource en
Windows 20.1.7.6. Cargando un BMP en nuestra ventana 20.1.8. Objetos en nuestra
esperando el comienzo del retrazo 29.1.2.3. Rebote de pelota mediante pantalla virtual
29.1.2.4. Rebote de varias pelotas mediante pantalla virtual
30. Texto en modo grfico
30.1. Texto en modo grfico 30.1.1. Fuentes del sistema 30.1.1.2. Soporte del BIOS de vdeo
30.1.1.3. Caracteres por defecto en VGA y MCGA 30.1.2. Generador de caracteres software
30.1.2.1. Manipulacin de pixels 30.1.2.2. Recorte 30.1.3. Ejemplos 30.1.3.1. Fuentes 8x8 de
la BIOS 30.1.3.2. Fuentes 8x16 de la BIOS 30.1.3.3. Fuentes 8x16 del usuario 30.1.3.4. Otras
fuentes del usuario 30.1.5. Ms all
31. Seno y coseno
31.1. Funciones seno y coseno 31.1.1. Definicin 31.1.1.1. Razones trigonomtricas 31.1.2.
Metodologa 31.1.2.1. Regla de clculo 31.1.3. Ejemplo: espiral 31.1.3.1. Ejemplo con tablas
pregeneradas 31.1.3.2. La base de la figura 31.1.3.3. Espiral con coprocesador
32. Grficos fractales
32.1. Grficos fractales 32.1.1. Definicin de fractal 32.1.1.1. La idea de dimensin 32.1.1.2.
Definicin de fractal 32.1.1.3. Dimensin de Hausdorff-Besicovitch 32.1.2. Fractales lineales
32.1.2.1. Polvo de Cantor 32.1.2.2. Tringulo de Sierpinski 32.1.2.3. Curva de Koch 32.1.2.4.
Curvas de Hilbert 32.1.2. Fractales no lineales o complejos 32.1.3.1. Conjuntos de Julia
32.1.3.2. Conjunto de Mandelbrot 32.1.4. Caos 32.1.4.1. Diagrama de bifurcacin 32.1.4.2.
Atractor de Lorenz 32.1.5. L-Systems 32.1.6. Plasma fractal 32.1.6. Fuego fractal 32.1.8.
Generacin de terrenos 32.1.9. Nubes
33. Animacin
33.1. Animacin 33.1.1. Operaciones de pixel bit a bit 33.1.1.1. XOR 33.1.1.2. NOT 33.1.1.3.
AND 33.1.1.4. OR 33.1.2. El teclado 33.1.3. Doble, triple y n-buffering 33.1.4. Teselado de
bloques de bits 33.1.5. Animacin 33.1.5.1. Restaurar el fondo
34. Ejemplos de programas grficos
34.1. Ejemplos de programas grficos 34.1.1. Volcar pantalla a BMP 34.1.2. Rebote 34.1.3.
Bump mapping 34.1.4. Curva de Ceva 34.1.5. FeedBack 34.1.6. Lupa 34.1.6.1. Lupa sobre
cuadrados 34.1.6.2. Lupa sobre baldosas 34.1.6.3. Lupa sobre imagen 34.1.7. Nieve
34.1.7.1. rboles de Navidad 34.1.7.2. Nevada 34.1.8. Plasma 34.1.8.1. Plasma dinmico
34.1.8.2. Plasma con doble bfering 34.1.9. Lluvia 34.1.10. Shade Bob 34.1.11. Sprite
34.1.11. Suelos 34.1.11.1. Suelo cuadrados simple 34.1.11.2. Suelo cuadrados con retraso
34.1.11.3. Suelo orfebre dinmico 34.1.11.4. Suelo de estrellas
35. Space Invaders
35.1. Ejemplo de space invaders 35.1.1. Juego invaders recogiendo BIOS-ticks 35.1.2. Juego
invaders interceptando Int 1Ch 35.1.3. Juego invaders usando counter0-PIT 35.1.4. Juego
invaders leyendo contador del canal 0 del PIT 35.1.5. Juego invaders interceptando Int 1Ch
con msica de fondo (entrecortado) 35.1.6. Juego invaders interceptando Int 1Ch con
msica de fondo (correcto)
36. Introduccin a la programacin 3D
36.1. Introduccin a la programacin 3D
37. Algunos ejemplos en 3D
37.1. Algunos ejemplos en 3D
Apndices
A. Caracteres ASCII
B. Saltos Condicionales
C. Debug
C.1. Debug C.1.1. Ejecucin del programa C.1.2. Comandos de Debug C.1.2.1. A C.1.2.2. D
C.1.2.3. E C.1.2.4. G C.1.2.5. N C.1.2.6. P C.1.2.7. Q C.1.2.8. R C.1.2.9. T C.1.2.10. U
C.1.2.11. W
D. rea de datos de la BIOS
D.1. rea de datos de la BIOS D.1.1. Datos del sistema D.1.2. Datos del adaptador de
pantalla
E. Puertos de entrada y salida
F. Cdigos scan del teclado
F.1. Cdigos scan del teclado F.1.1. Teclas de funciones F.1.2. Teclado numrico F.1.3. Teclado
alfabtico F.1.4. Teclado numrico (sobre el teclado alfabtico) F.1.5. Miscelnea
G. Optimizaciones
G.1. Optimizaciones G.1.1. Limpiar registros G.1.2. Registro BP G.1.2. Nos aprovechamos del
cdigo G.1.3. Incrementos G.1.4. Multiplicacin y divisin por potencias de dos G.1.5.
Espacio de memoria reservado pero no inicializado G.1.6. Mover y almacenar palabras en
lugar de bytes G.1.7. Evitar saltos G.1.8. Tamao de las variables G.1.9. Ejemplo
H. MS-DOS
H.1. MS-DOS H.1.1. Qu es H.1.2. Dnde encontrarlo H.1.3. El indicador de comandos
(PROMPT) H.1.4. Cambiar de directorio H.1.5. Limpiar la pantalla H.1.6. Directorio H.1.7.
Crear un directorio H.1.8. Creacin de un archivo H.1.9. Visualizacin de un archivo H.1.10.
Archivos BATCH H.1.10.1. Comentarios H.1.10.2. Impresin H.1.10.3. Etiquetas H.1.10.4.
Saltos H.1.10.5. Flujo H.1.10.6. Bucles H.1.10.7. Pausas H.1.10.8. Parmetros H.1.10.11.
Ejemplos H.1.11. Borrar ficheros H.1.12. Borrar directorios
I. Instrucciones 8087 (por orden alfabtico)
J. Grandes proyectos en ensamblador
J.1. Grandes proyectos en ensamblador J.1.1. Flat assembler J.1.2. MenuetOS
K. Declogo de buenas prcticas
Otros
Prembulo
Qu es Abre los Ojos al Ensamblador
Realmente no es un libro. Son las notas bien organizadas y estructuradas en mi camino de
aprendizaje del lenguaje ensamblador.
Cmo he aprendido a programar en Ensamblador
El formato ha sido absolutamente autodidacta. Decenas de horas buscando informacin en
internet. Estudindome programas escritos en otros lenguajes. Libros en ensamblador y
otros lenguajes. Cientos de horas persiguiendo al dichoso programa que no acaba de
funcionar. Especialmente difcil ha sido encontrar informacin en ensamblador respecto a
las listas y rboles, de hecho no encontr ninguna.
Por qu tres compiladores: MASM, FASM, NASM
Buena pregunta!. Yo mismo me la he hecho muchas veces, sobre todo cuando tena que
traducir un programa correcto a los otros y tena que perseguir los errores durante horas.
En principio comenc con MASM, cmo no?. Es el que tiene ms antigedad y, por tanto,
ms recorrido, as como abundante bibliografa y recursos por internet. Adems, su uso se
tambin habr cdigo escrito hace tiempo que ahora mismo enfocara de forma diferente o
que abreviara de forma ms elegante. S que hay fallos, como en todo, por ejemplo en los
comentarios de los registros que se modifican dentro de una rutina, estn dentro de los
temas pendientes. Se espera que te lo leas bien, lo asimiles, modifiques los puntos que
necesites y, finamente, tomes tu propia decisin.
Cosas que modificaras del libro
Probablemente haya muchas, pero repito que es mi experiencia personal, en l he incluido
lo que me pareca interesante, como me pareca adecuado. Es posible que en algunos
puntos consideres el texto excesivo y en otros escasos, pero es fruto de mi gusto.
Por qu deberas aprender ensamblador
Por qu no?. Pensaba dejarlo aqu, pero aadir una cosa ms: si te gusta programar, te
gustar el ensamblador.
Por qu Abre los Ojos al Ensamblador no es gratuito
Esta afirmacin no es cierta, lo nico que no es gratuito son las bibliotecas que se utilizan
para compilar muchos programas del libro, pero tanto el texto como amplias partes de l,
como son la programacin en Windows o las interfaces con lenguajes de alto nivel s que lo
son, en la medida en que estn accesibles ntegramente. De hecho tampoco he puesto
mucho nfasis en esto, por ejemplo tambin est completo el programa Tetris.
Dicho esto y respondiendo a la pregunta, es evidente que no espero hacerme rico con el
lenguaje ensamblador a estas alturas, pero s me gustara que cubriese los gastos y, si me
diese tambin para alguna entrada de cine, pues estupendo. El libro no est completo y me
gustara hacerlo lo ms participativo posible, pero el ensamblador no es la nica ocupacin
que tengo, de hecho slo es una aficin, y le dedicar tanta atencin como la despierte
entre la gente.
Cabe resear que el costo del registro se considera como un donativo y, por lo tanto, no
tiene ninguna clase de implicaciones para mi persona. Abre los Ojos al Ensamblador no lleva
aparejado el soporte ni la devolucin del coste del registro, adems, se puede considerar
que tienes todo el tiempo del mundo para probarlo antes de registrarte y te exhorto a que
as lo hagas, tmate tu tiempo, revsatelo bien y, cuando ests convencido, realiza el pago
del registro. La novedad es que ya no hay registro, dejo como ejercicio las libreras.
Muy importante tambin. Debes considerar que ninguna obra est libre de fallos y sta no
es una excepcin. De ningn modo me puedo considerar responsable de las
consecuencias debidas o indebidas que se puedan suceder del uso que le des a la
informacin, programas, cdigo, etc que aqu (en el libro Abre los Ojos al
Ensamblador) existen, slo t eres el responsable.
Por qu cuesta 10 euros el registro
Es un nmero redondo y lo suficientemente bajo como para que sea accesible por cualquier
persona. Pues eso, las libreras ya no se venden.
Qu es el foro
Es un punto de encuentro entre todos aquellos a los que nos gusta el ensamblador para
intercambiar opiniones y aprender unos de otros, yo tambin.
Qu no es el foro
No es un punto de soporte para Abre los Ojos al Ensamblador ni para cualquier duda que te
pueda surgir. Tampoco estoy obligado a crearlo ni a mantenerlo.
Puedo usar la informacin o cdigos aqu descritos en mi propio proyecto?
Claro, slo tienes que darme crdito donde corresponda. Lo que no es admisible es que tu
proyecto consista en hacer otro Abre los Ojos al Ensamblador cambiando el autor por tu
nombre. Un mximo de un 20%-30% de AOE en tu proyecto podra ser aceptable, aunque es
deseable que intentes innovar, no copiar.
He visto que quedan cosas pendientes, tendr que volver a pagar el registro
cuando estn terminadas?
No, el registro es para todo el libro Abre los Ojos al Ensamblador, est todo terminado o no.
Slo t eres el responsable
Para que quede bien claro, le pongo un ttulo. Debes entender que este libro puede contener
informacin, cdigo, etc. que sean incorrectos. Tambin puede ocurrir que, siendo correctos,
t hagas un mal uso de ellos. Da igual, en cualquier caso el responsable del uso que hagas
de la informacin, datos, cdigo, programas, etc. de este libro slo eres t.
Por favor, no te olvides de mirar los trminos legales de uso del libro.
Puedes ver que hemos empleado el 10 como base en todas las exponenciaciones, por eso se le llama de
base 10.
8 + 4 + 0 + 1
13
Explicacin:
Como en base decimal, siempre empezamos por la derecha y decimos:
1 ms 1 son 2 (en decimal), que en binario se representa con un 10, por lo tanto, ponemos un cero
y nos llevamos una.
0 ms 1 es 1, ms 1 que nos llevbamos de antes, son 2 (en decimal), que de nuevo, en binario se
representa por un 10, por lo que ponemos un cero y nos llevamos una.
1 ms 0 es 1, ms 1 que nos llevbamos de antes, son 2 (en decimal), que en binario es 10, con lo
que ponemos un cero y nos llevamos 1.
1 ms 1 son 2, ms 1 que nos llevbamos antes son 3 (en decimal), que en binario se representa por
un 11, que es lo que ponemos, et voil.
= 8 + 4 + 1 = 13d
= 8 + 2 + 1 = 11d
--=
2
= 2d
Explicacin:
De nuevo, al igual que en base 10 empezamos por la derecha y decimos:
X and Y
X or Y
X xor Y
not X
not X es el opuesto de X
4787
Para pasar un nmero de decimal a hexadecimal utilizaremos el teorema del cociente en el anillo :
Binario
Hexadecimal
Binario
Hexadecimal
0000
1000
0001
1001
0010
1010
0011
1011
0100
1100
0101
1101
0110
1110
0111
1111
Es as de sencillo.
Vamos a convertir ahora un nmero binario en hexadecimal. Para hacer esto, tan slo tenemos que
asegurarnos que el nmero de cifras que tiene nuestro nmero es mltiplo de 4, porque vamos a volver a
utilizar la tabla anterior. Supongamos, por ejemplo, el nmero 1011001010b. Lo primero que tenemos que
hacer es aadirle dos ceros a la izquierda para que tenga un nmero de dgitos mltiplo de cuatro, y luego,
la operacin es justo la inversa de la anterior.
0010 1100 1010
2
C
A
1.1.7.1. Bit
Es la unidad ms pequea de informacin, puede contener slo un 0 un 1.
1.1.7.2. Nibble
Es una coleccin de cuatro bits. No es una estructura de especial inters salvo para dos objetos:
1. El BCD, que es una forma de representar nmeros en formato ASCII en 4 bits
2. Los dgitos hexadecimales, cada uno de ellos tiene una representacin de 4 bits.
Con un nibble se pueden representar hasta 24 = 16 valores diferentes.
1.1.7.3. Byte
Es la ms importante estructura de datos, pues es el tamao de dato ms pequeo accesible por un 8086 y
est compuesta por 8 bits, o sea, 2 nibbles, y por tanto son representados por 2 dgitos en hexadecimal.
7
1.1.7.4. Palabra
Es un grupo de 16 bits, o equivalentemente, 2 bytes 4 nibbles; por lo que puede ser representado por un
nmero hexadecimal de 4 dgitos. Es tambin una estructura muy importante porque todos los registros
del 8086 son de 16 bits, que es con la unidad con la que fue diseada para trabajar. Esto quiere decir que el
microprocesador 8086 es de 16 bits.
15
14
13
12
11
10
09
08
07
06
05
04
03
02
01
00
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
09
08
07
06
05
04
03
02
01
00
Una cudruple palabra puede representar hasta 264 = 18.446.744.073.709.551.616 valores diferentes.
Actualmente tambin existen microprocesadores de 64 bits profusamente extendidos entre los PCs.
Propiedad asociativa: a + (b + c) = (a + b) + c
Propiedad conmutativa : a + b = b + a
Puesto que la capacidad de los ordenadores es limitada, establecemos unas magnitudes de dimensiones:
Existen ms, pero estos son los ms usados. Todos ellos estn pensados naturalmente para albergar
nmeros enteros positivos hasta su lmite, pero cmo podemos almacenar nmeros negativos?.
Realmente tenemos que usar un truco que es establecer la mitad de su capacidad para los nmeros
positivos y la otra mitad para los negativos.
El sistema ms comnmente utilizado se denomina "complemento a dos", y se basa en las siguientes
reglas:
Un nmero positivo tiene su bit ms significativo (el de la izquierda) siempre a cero, y a uno si es
negativo.
Para convertir un nmero positivo en negativo (o viceversa) se invierten todos los bits del nmero,
y luego se le suma uno al resultado.
Por ejemplo:
35d = 00100011b -> (invert) -> 11011100b -> +1 -> 11011101b = -35d
-35d = 11011101b -> (invert) -> 00100010b -> +1 -> 00100011b = 35d
Supongamos que cogemos un nmero de magnitud byte, esto significa que slo puede contener 8 dgitos,
ceros o unos.
Grficamente el sistema "complemento a dos" quedara como sigue:
Compl a 2
Hexadecimal
-128
1000 0000
128
80
-127
1000 0001
129
81
-126
1000 0010
130
82
[...]
[...]
[...]
[...]
-3
1111 1101
253
FD
-2
1111 1110
254
FE
-1
1111 1111
255
FF
0000 0000
0000 0001
0000 0010
0000 0011
[...]
[...]
[...]
[...]
125
0111 1101
125
7D
126
0111 1110
126
7E
127
0111 1111
127
7F
La cifra que obtenemos excede de tamao byte, puesto que tiene 9 dgitos, por lo tanto el dgito de la
extrema izquierda se pierde, es como si intentaras llenar una botella con vasos de agua y el ltimo no
cupiese, simplemente se desbordara y se perdera. De esta forma qu es lo que obtenemos?, el nmero
0b, con lo que obtenemos este crculo vicioso del que hablbamos antes. Esto ocurre por la ya mencionada
limitacin de contencin de cualquier nmero de las computadoras y a este suceso se le llama
desbordamiento. La nica solucin para que no ocurran desbordamientos (puesto que obtenemos
resultados imprevisibles) es elegir una botella lo suficientemente grande como para que quepan todos los
vasos de agua que le vamos a echar.
Sean los nmeros:
b = 0000 0010b = 2d
En el caso de que tratemos con enteros con signo se observa inmediatamente que el nmero a es negativo,
puesto que su dgito de extrema izquierda (el de mayor peso) es 1. Para ver su representacin decimal hay
que invertir sus bits y sumarle un 1 decimal.
Este subconjunto de Z, en el caso de los bytes de -128 a 127, con esta operacin suma en complemento a 2
que hemos definido es un subgrupo:
Es cerrado respecto de la suma. Si notamos al subconjunto como B, b y b' dos elementos suyos,
b+b' tambin es de B por la propiedad del desbordamiento.
1000 0001b
0111 1111b
------------ +
1 0000 0000b
Cada elemento tiene su simtrico. Dado g en G, su simtrico ser: NOT(g) + 1. NOT cambiar
cada bit a su contrario, y luego le sumamos 1. nicamente el 128 se escapa de esta propiedad
porque -128 es un byte, pero 128 ya es un word. As ([-127,127], suma complemento a 2) sera un
subgrupo de (Z,+), pero el -128 tambin cabe dentro de un byte.
Propiedad conmutativa.
1000 0001b
0000 0010b
0000 0010b
1000 0001b
----------- +
---------- +
1000 0011b
1000 0011b
1000 0011b = -(0111 1100b + 1d) = -(124d + 1d) = -125d = -127d + 2d.
+ 1b = 01111111b + 1b = 10000000b =
+ 1b = 01111110b + 1b = 01111111b =
+ 1b = 01111101b + 1b = 01111110b =
127d
126d
+ 1b = 00000001b + 1b = 00000010b =
+ 1b = 00000000b + 1b = 00000001b =
+ 1b = 11111111b + 1b = 00000000b =
2d
1d
+ 1b = 11111110b + 1b = 11111111b =
+ 1b = 11111101b + 1b = 11111110b =
-1d
-2d
Importante
Antes de realizar operaciones con nmeros con signo es preciso cerciorarse de que todos tengan el mismo
nmero de bits. Si esto no es as hay que alargar el tamao de los ms cortos al tamao del mayor. Para
ello se repite la cifra a la izquierda tantas veces como sea necesario, es decir, a los nmeros negativos se
les aade 1 repetidas veces a la izquierda y 0 a los positivos. Esto ya se consigue con los operadores
CBW, CWD, por ejemplo.
Otra cosa son los enteros sin signo. Por ejemplo, de tipo byte, que son 8 bits seran 28=256 elementos, que
van desde el 0 hasta el 255. Aqu ya no tenemos la suma en complemento a 2, sino la suma normal, pues
no existen los negativos, pero el desbordamiento sigue existiendo, lo cul provoca que el nmero
resultante de la suma siga siendo de tipo byte, pero el resultado sera distinto al esperado. Por ejemplo:
244d = F4h = 11110100b
128d = 80h = 10000000b
------------------------- +
372d = 174h = 101110100b
Vemos que el nmero binario resultante de la suma tiene 9 dgitos, se pierde entonces el de la extrema
izquierda, quedando:
116d =
74h =
01110100b
Obsrvese que un byte slo puede tener dos dgitos hexadecimales, pues FFh = 255d.
Al igual que ocurra con los nmeros negativos, el ordenador no trata directamente con este tipo de
nmeros, sino que se vale de un artificio para ello. Tampoco existe una capacidad infinita para ellos,
lgicamente.
Nosotros vamos a ver slamente tres tipos de nmeros en coma flotante, descritos en la siguiente tabla:
Tipo de dato
Bits Bytes
Dgitos significativos
Rango aproximado
Real Corto
32
6-7
Real Largo
64
15-16
Real Extendido
80
10
19
Rango de exponente
Real Corto
-127 a +128
Real Largo
-1023 a +1024
Real Extendido
-16383 a 16384
Tabla 01-08 - Rango de Exponentes
En binario tenemos:
39.5625 = 32+4+2+1+0.5+0.0625 =
1x25+0x24+0x23+1x22+1x21+1x20+1x2-1+0x2-2+0x2-3+1x2-4
La segunda parte consiste en convertir la parte decimal a binario. Para ello utilizamos un procedimiento
semejante al anterior, slo que ahora en lugar de dividir por 2, multiplicamos por 2 y vamos cogiendo la
parte entera que nos va saliendo hasta que nos quedemos sin decimales:
Parte decimal
*2
Parte entera
0,5625
1,1250
0,1250
0,2500
0,2500
0,5000
0,5000
1,0000
El bit ms significativo tanto de los 32 de real corto, como de los 64 del real largo, como de los 80
del Real extendido est reservado para almacenar el signo del nmero: 0 para positivo, 1 para
negativo.
Los siguientes 8 bits del real corto, 11 para el real largo y 15 para el Real extendido, estn
reservados para guardar el exponente del nmero, y para trabajar con exponentes positivos y
negativos, ste est discriminado por una suma de 127 (27-1) en el caso de reales cortos, 1023 (2101) para los reales largos y 16383 (214-1) para los Reales extendidos.
El resto de los bits se reservan para la mantisa del nmero exponencial. Es importante decir que el
1 de la parte real de la mantisa no se guarda puesto que se asume que siempre es as. En caso del
nmero real 0, toda la estructura que comentamos tendr todos sus bits a cero.
EXP
31
30
MANTISA
23
22
EXP
63
62
MANTISA
52
51
EXP
79
78
MANTISA
64
63
El signo es positivo
El exponente 5d+127d = 132d = 10000100b
La mantisa 001111001
Con lo cul, se guardara en un espacio de memoria de 32 bits as:
0 10000100 00111100100000000000000b = 421E4000h
Si estamos trabajando en un entorno de 16 bits, esto se recogera en DX:AX as: DX = 421E, AX = 4000 y
se guardara en formato Little Endian as: 00 40 1E 42.
Algunos ejemplos:
0
1
0
1
00000000
00000000
11111111
11111111
00000000000000000000000b
00000000000000000000000b
00000000000000000000000b
00000000000000000000000b
=
=
=
=
Cero Positivo
Cero Negativo
Infinito positivo
Infinito negativo
Obsrvese que multiplicar un nmero X en binario por 2n equivale a correr la coma decimal de X n veces
a la derecha si n es positivo, y a la izquierda si n fuera negativo
Por ejemplo, veamos cmo calculamos la representacin decimal del binario 101.011:
La parte entera:
101b=5d.
La parte decimal:
0*2-1+1*2-2+1*2-3 = 1/4d+1/8d=3/8d=0,375d
RealCM01
RealCJ01
RealCN01
RealCF01
Cdigo
Cdigo
Cdigo
Cdigo
[bin]
[bin]
[bin]
[bin]
Resultado en pantalla
>RealCF01
.0004998
*2
Parte entera
0,1
0,2
0,2
0,4
0,4
0,8
0,8
1,6
0,6
1,2
0,2
0,4
x'' est ms prximo a x que x', por lo que la representacin de x ser x''.
Vamos a ver ahora mediante un ejemplo cmo la representacin de un nmero en coma flotante pierde
precisin frente a los nmeros enteros:
Para empezar, el espacio utilizado para representar un nmero en coma flotante hay que dividirlo para
guardar el exponente y la mantisa, mientras que el nmero entero usa todo el espacio para la mantisa. Esto
significa que el formato para representar nmeros en coma flotante tendr menos precisin que el formato
entero.
Supongamos que tenemos el siguiente formato en 8 bits para representar nmeros en coma flotante:
EEE MMMMM
3
5
El exponente no va a estar biselado, con lo que podr representar exponentes desde el 0 hasta el 7 y la
mantisa usa el bit 1 por defecto de la parte entera numrica.
Si el exponente es 0 y la mantisa es 0, el nmero ms pequeo que podremos representar ser 1,0x20 = 1.
Si el exponente y la mantisa tienen todos sus bits a 1, el nmero ms grande que podremos representar
ser 1,11111x27 = 11111100b = 252d.
Por otra parte usando el formato de 8 bits para guardar un entero, tenemos que el nmero ms pequeo
que puede representar es 0 y el mayor es 28-1 = 255.
Para empezar, ya estamos viendo que el nmero de enteros que abarca es mayor que el de coma flotante, si
bien ste puede representar nmeros decimales que el otro no puede, claro.
Vamos a ver ahora una curiosa prdida de datos mediante este mtodo de representar nmeros en coma
flotante. Si el mayor nmero representable es 252, cul es su inmediato anterior?. Sera 1,11110 x 27 =
11111000b = 248d.
Es decir que antes del 252 va el 248, nos hemos comido el 249, 250, 251!, que la representacin entera s
posee.
Asmismo, el siguiente en la lista sera
1,11101 x 27 = 11110100b = 244d.
Nos hemos vuelto a saltar 4 valores.
El montante del error es mayor para los valores ms altos, puesto que la prdida de precisin en la mantisa
es amplificada por el exponente. Cuanto ms pequeo es el valor, menor es el error en la precisin.
Direccin+0
Direccin+1
Direccin+2
Direccin+3
Byte0
Byte1
Byte2
Byte3
Big Endian acta justo al revs, es decir, el byte ms alto de la estructura multibyte se almacena en la
direccin de memoria ms pequea y el byte ms bajo en la direccin ms grande. La estructura multibyte
anterior, se almacenara as:
Base
Base
Base
Base
Direccin+0
Direccin+1
Direccin+2
Direccin+3
Byte3
Byte2
Byte1
Byte0
Comentario
La distribucin Little Endian la utilizan microprocesadores tales como el de Intel, y la del Big Endian
microprocesadores como los de Motorola, como los que usan los ordenadores "Apple". Obsrvese que
con la primera estructura, que va a ser la que nosotros utilizamos, vamos a ver que los pares de dgitos
hexadecimales que forman un byte se guardan en "orden inverso" al que posee la estructura multibyte.
Esta caracterstica quizs nos desconcierte un poco al principio, pero enseguida se le coge el manejo.
No vamos a entrar aqu en el agrio debate que suscitan los pros y contras de cada uno de ellos, en cambio
vamos a ver un ejemplo ilustrativo de cmo se guarda un entero de tipo LongInt (4 bytes) usando la
distribucin Little Endian. Para ello vamos a utilizar el depurador AFD, que es sencillo de utilizar y
gratuito.
El cdigo fuente del programa LEndian.asm es el siguiente:
;
;
;
;
;
;
;
Hemos definido una variable de tipo LongInt de 4 bytes llamada "miLongInt" con el valor 0ABCDEF01h.
Le ponemos un cero delante porque sino el ensamblador supondra que se trata del nombre de una
etiqueta. Vamos ahora a ver cmo se guarda esta variable en memoria. Para ello utilizamos el programa
AFD como hemos dicho. Sabemos que este valor se guarda a partir de la direccin de memoria 102h
porque en el lugar correspondiente a la instruccin mov dx, word ptr miLongInt aparece en el volcado
hexadecimal MOV AX, [0102]. Nos desplazamos entonces a la parte de abajo correspondiente al
segmento de datos DS mediante la tecla "F8" y avanzamos con la tecla "Av. Pag." hasta que llegamos a
este lugar de memoria. Tras ejecutar las instrucciones hasta llegar a mov ax, 4c00h para meter en DX y
AX el valor alto y bajo de miLongInt respectivamente, que podemos ver en Fig. 01-04.
1.2. Registros
Dentro del procesador 8086 existen 14 registros de 16 bits, su misin es almacenar datos o direcciones de
memoria de forma temporal a lo largo del programa. Hay que utilizarlos siempre que se pueda porque los
accesos a memoria son mucho ms lentos que los accesos a los registros. Adems, hay ciertas operaciones
que slo se pueden realizar sobre los registros. Hay registros que tienen caractersticas especiales, los hay
que estn especializados en una determinada accin y no todos sirven para realizar algn proceso en
concreto. Por ejemplo:
AX, BX, CX, DX pueden utilizarse como registros de 16 bits o el byte superior e inferior por separado
como sendos registros de 8 bits. No hay ningn otro registro con esta caracterstica.
Registro AX. Es el acumulador principal, utilizado para operaciones que implican entrada/salida y
la mayor parte de la aritmtica.
Registro BX. Es el registro base. Es el nico de proposito general que puede ser un ndice para
direccionamiento indexado, as como empleado para clculos.
Registro CX. Es el registro contador. Es muy utilizado con la orden loop para repetir un ciclo.
Tambin es usado para el corrimiento de bits y para muchos clculos.
Registro CS (CODE SEGMENT). El DOS almacena la direccin inicial del segmento de cdigo
de un programa en el registro CS. Esta direccin de segmento, ms un valor de desplazamiento en
el registro de apuntador de instruccin (IP), indica la direccin de una instruccin que es buscada
para su ejecucin. Para propsitos de programacin normal, no se necesita referenciar el registro
CS.
14
13
12
11
10
09
08
07
06
OF
DF
IF
TF
SF
ZF
05
04
AF
03
02
PF
01
00
CF
CF (Carry Flag). Indicador de acarreo. Su valor ms habitual es lo que nos llevamos en una suma o
resta.
PF (Parity Flag). Indicador de paridad. Se activa tras algunas operaciones aritmeticolgicas para
indicar que el nmero de bits a uno resultante es par.
14
13
12
Nibble 3
11
10
09
08
Nibble 2
07
06
05
04
Nibble 1
AH
03
02
01
00
01
00
01
00
01
00
01
00
Nibble 0
AL
Tabla 01-13 - Registro AX
15
14
13
12
Nibble 3
11
10
09
08
Nibble 2
07
06
05
04
Nibble 1
BH
03
02
Nibble 0
BL
Tabla 01-14 - Registro BX
15
14
13
12
Nibble 3
11
10
09
08
Nibble 2
07
06
05
04
Nibble 1
CH
03
02
Nibble 0
CL
Tabla 01-15 - Registro CX
15
14
13
12
Nibble 3
11
10
09
08
Nibble 2
07
06
05
04
Nibble 1
DH
03
02
Nibble 0
DL
Tabla 01-16 - Registro DX
14
13
12
11
10
09
08
07
06
05
04
03
02
14
13
12
11
10
09
08
07
06
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
05
04
03
02
01
00
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
14
13
12
11
10
09
08
07
06
OF
DF
IF
TF
SF
ZF
AF
PF
CF
OUT transfiere informacin desde un registro a un puerto, si es un byte y desde AX si es una palabra. El
formato general es:
OUT puerto, reg-acum
IN AL, puerto
OUT puerto, AX
; Entrada de un byte
; Salida de una palabra
Dinmicamente: Podemos utilizar el contenido del registro DX de 0 a 65.535 indirectamente, puede ser
adecuado para ir incrementando DX a la vez que se van procesando las direcciones de los puertos. Veamos
el siguiente ejemplo:
MOV DX, 60h
IN AL, DX
AH, 00h
AL, char
DX, 0
21h
;
;
;
;
64 Kb (64 Kb es 216 bytes = 65.536 bytes). Cmo acceder entonces al megabyte de memoria?. Una
posible solucin consista en utilizar dos de nuestros registros de 16 bits, lo cul equivaldra a utilizar un
registro de 32 bits, pero por aqul entonces probablemente pensaron que nadie habra de necesitar nunca
tanto, por lo cul idearon un sistema denominado segmentacin que consiste en dividir la memoria en
grupos de 64 Kb. Cada grupo se asocia con un registro de segmento de 16 bits; el desplazamiento dentro
de cada segmento lo proporciona otro registro de 16 bits. Para alcanzar los 20 bits multiplicamos por 16 el
valor del registro de segmento y sumamos el desplazamiento. Obsrvese que multiplicar por 24=16
equivale a correr el nmero cuatro posiciones a la izquierda y los cuatro dgitos de la derecha se rellenan
con ceros, mientras que dividir por 16 equivaldra a correr el nmero 4 dgitos de la derecha y los cuatro
de la izquierda se rellenan con cero.
OFFSET = SEGMENT * 16
SEGMENT = OFFSET / 16 (perdemos los 4 bits inferiores)
direccin = segmento * 16 + desplazamiento
SEGMENT
0010010000010000---OFFSET
----0100100000100010
Direccin de 20 bits 00101000100100100010
Por ejemplo, con DS:SI
====== DS ======
====== SI ======
Esta es la forma DS:SI con la que accedemos a 20 bits con dos registros de 16 bits. El segmento en DS y
el desplazamiento en SI. Obsrvese que DS y SI se solapan, esto implica que existe ms de una forma de
acceder a la misma direccin de memoria, por ejemplo, 3D00h:0300h es equivalente a 3D30:0000h.
Veamos por qu:
Tngase en cuenta que 16 decimal equivale a 10 hexadecimal. Y como sabemos, multiplicar por 10
equivale a aadir un cero a la derecha. Pues bien, vamos a encontrar la direccin de memoria accedida por
estas segmentaciones:
3D00h:0300h => direccin = 3D00h * 10h + 0300h = 3D000 + 0300h = 3D300h
3D30h:0000h => direccin = 3D30h * 10h + 0000h =
= 3D300h
ADD
dato
MOV
DATO
MOV
AX,
EQU
AX,
dw
AX,
0FFFh
0FFFh
dato
0FFFh
OFFSET dato
Indirecto con ndice o indexado. El operando se encuentra en una direccin determinada por la
suma de un registro de segmento*16, un registro de ndice Si o DI y un desplazamiento de 8 16
bits.
Indirecto con base e ndice o indexado a base. El operando se encuentra en una direccin
especificada por la suma de un registro de segmento*16, uno de base, uno de ndice y
opcionalmente un desplazamiento de 8 16 bits.
; AX = [SS*16+BP]
; [ES*16+DI] = AX
; AX = desp[DI]
; desp[SI] = BX
; AX = ES:desp[BX][DI]
; CS:desp[BX][SI] = CX
Corto. Si es alcanzada por medio de un desplazamiento y est limitada a una distancia de -128 a
127 bytes.(8 bits)
Lejano. Si est en otro segmento y es alcanzada por medio de una direccin de segmento y un
desplazamiento.
1.4.3. La pila
Es un bloque de memoria de estructura LIFO ("Last Input First Output": ltimo en entrar, primero en
salir), grficamente podra decirse que tiene una estructura de una pila de platos: el primero se coloca
sobre la mesa, el segundo sobre el primero, el tercero sobre el segundo y as sucesivamente; y cuando
vamos a coger un plato, el primero que cogemos es el ltimo que pusimos, el de ms arriba.
El tamao de la pila hay que definirlo en un archivo EXE, si es un archivo COM el DOS establece la pila
al final del segmento de 64K y carga el registro SP con FFFEh, la parte superior de la pila (el tope de la
pila) si el segmento de 64K es suficientemente grande. Se incrementa en direccin a los datos.
La pila se direcciona mediante desplazamientos desde el registro SS (stack segment). Las posiciones
individuales dentro de la pila se calculan sumando al contenido del segmento de pia SS un desplazamiento
contenido en el registro puntero de pila SP. Todos los datos que se almacenan en la pila son de longitud
palabra, y cada vez que se introduce algo en ella por medio de las instrucciones de manejo de pila (PUSH
y POP), el puntero se decrementa en dos; es decir, la pila avanza hacia direccines decrecientes. El registro
BP suele utilizarse normalmente para apuntar a una cierta posicin de la pila y acceder indexadamente a
sus elementos, generalmente en el caso de variables, sin necesidad de desapilarlos para consultarlos.
La pila es utilizada para preservar el valor de un registro o de una variable de 16 bits (1 palabra)
metindola en la pila con la orden PUSH que salvamos para recuperarla posteriormente con la orden POP
que cogemos. Las rdenes POP deben hacerse justo en orden inverso a las PUSH puesto que la pila tiene
estructura LIFO. Su empleo es la nica forma de definir variables locales. Tambin es utilizada
internamente para cargar el IP cuando llamamos a una subrutina y luego se recoge ste. Tambin se puede
emplear para pasar parmetros a los procedimientos.
Puesto que la pila va a ser muy utilizada, tanto por el programador como por operaciones internas, es muy
necesario ir desapilando todo lo apilado para evitar una prdida de control sobre el ordenador por
desbordamiento de sta.
Los bytes en memoria se numeran en forma consecutiva, iniciando con 00, de modo que cada localidad
tiene un nmero de direccin nico.
Aqu abajo vemos un mapa fsico de la memoria del PC tipo 8086. Del primer megabyte de memoria, los
primeros 640K los ocupa la RAM, la mayor parte de la cul est disponible para su uso.
Inicio
Direccin
Uso
Dec 960K
Hex F0000
768K
C0000
640K
A0000
0K
Memoria Superior
Memoria Convencional
ROM. Es un chip especial de memoria que slo puede ser leda. Debido a que las instrucciones y
los datos estn "grabados" permanentemente en un chip de ROM, no pueden ser alterados. El
Sistema Bsico de Entrada/Salida (BIOS) de ROM inicia en la direccin 768K y maneja los
dispositivos de entrada/salida, como un controlador de disco duro. La ROM que inicia en 960K
controla las funciones bsicas de la computadora, como la autoprueba al encender, patrones de
puntos para los grficos y autocargador de disco. Cuando se enciende la computadora, la ROM
realiza ciertas verificaciones.
RAM. Un programador est preocupado principalmente con la RAM, que sera mejor llamada
memoria de lectura-escritura. La RAM se dispone como una "hoja de trabajo" para
almacenamiento temporal y ejecucin de programas. Ya que el contenido de la RAM se pierde
cuando se apaga la computadora, debe reservar almacenamiento externo para guardar programas y
datos.
rea de datos de BIOS. Se inicia en la localidad 0040:0000, que est estrechamente relacionada
con los dispositivos conectados. A continuacin el BIOS determina si est presente un disco que
contenga los archivos de sistema del DOS y, en caso de que as sea, accede al cargador de arranque
desde ese disco, cargando los archivos de sistema IO.SYS y MSDOS.SYS desde el disco hacia la
memoria y transfiere el control al punto de entrada del IO.SYS.
Sin embargo, esta forma de utilizar el nombre del segmento de cdigo slo es posible en programas de
tipo .EXE, en programas de tipo .COM ni si quiera es necesario, puesto que slo cuenta con un segmento.
La forma de definir un segmento mediante la sintaxis clsica de MASM es mediante una pareja de
directivas que marcan su comienzo y final. Estas directivas son SEGMENT para el comienzo y ENDS
para el final. Ambas van precedidas por el nombre que se le da al segmento y, en el caso de la primera, va
seguida de una serie de palabras que indican algunas caractersticas del segmento. Obsrvese que con la
sintaxis de NASM no es necesario definir el final del segmento, pues se considera implcito al inicio del
siguiente.
Las caractersticas o atributos que se aplican a la directiva SEGMENT son la alineacin, la combinacin y
la clase, las cuales pueden darse en cualquier orden. En caso de que se omitan algunos de estos cuatro
tipos de atributos, el ensamblador tomar para ellos sus valores por defecto.
1.4.6.1. Alineacin
Se utiliza para que el segmento comience en una direccin de memoria que sea mltiplo de un valor
determinado. Sus posibles valores son los siguientes:
Alineacin
Mltiplo de
BYTE
WORD
DWORD
PARA
16
PAGE
256
MEMPAGE
4096
Tabla 01-29 - Alineacin
El valor por defecto es PARA, el cul es utilizado en la mayora de las ocasiones, puesto que, al utilizar
una direccin mltiplo de 16 como comienzo hace que el segmento ensamblador coincida exactamente
sobre un segmento de memoria, formndose as una equivalencia entre ambos.
Obsrvese que el 8086 y 80286 tienen un bus de datos de 16 bits (una palabra), por lo que trabajan ms
rpido si acceden a datos con tamao de palabra. Supongamos el valor 8A9Bh que se encuentra en la
direccin de memoria 912-913, el procesador los podr recuperar en una sola pasada metindolos, por
ejemplo en el registro AX; sin embargo, si este mismo valor se encontrase en 911-912 tendra que
recuperarlo en dos pasos: primero leera 910-911, metiendo 9B en AL y luego leera 912-913 metiendo 8A
en AH. Vemoslo grficamente:
912
913
9B
8A
AL
AH
Tabla 01-30 - Primer caso
910
911
912
913
??
8A
9B
??
AH
AL
Tabla 01-31 - Segundo caso
Contamos con la directiva ALIGN para informar al ensamblador que nos alinee elementos en lmites. Por
ejemplo "ALIGN 2" alinea en un lmite de palabra. De forma que en un programa con muchos datos
resulta interesante su uso para acelerar el proceso de carga. Se emplea inmediatamente antes del dato que
queramos alinear. Tenemos el cdigo de ejemplo en "AlignC?1.asm". Evidentemente con esta directiva se
ocupa ms espacio, comprubese eliminndolo del cdigo y volviendo a compilarlo; sin embargo, para
una coleccin de varias palabras, slo necesitamos usarlo para la primera.
FASM MASM NASM Resultado en pantalla
Cdigo Cdigo Cdigo ; Salida con DEBUG:
[bin]
[bin]
[bin]
1.4.6.2. Combinacin
Especifica cmo debe combinarse el segmento con otros que tengan el mismo nombre y que se encuentren
en otros mdulos del programa.
Combinacin Forma de combinacin
PRIVATE
PUBLIC
STACK
El segmento se combina con otros del mismo nombre para formar la pila del programa
COMMON
Coloca el segmento en la mismas posiciones de memoria que otros con el mismo nombre
AT xxx
El segmento hace referencia al segmento fsico indicado por el valor numrico xxxx. Ese
tipo de segmentos se utilizan para acceder a memoria fuera del programa, como vectores
de interrupcin o datos de la BIOS
MEMORY
El segmento se colocar al final del programa, permitiendo utilizar la memoria que hay
ms all del mismo. Slo puede haber un segmento de este tipo y, si hay varios, el resto se
tratan como COMMON
VIRTUAL
Define un tipo de segmento comn a varios mdulos, pero que se define dentro de otro
Tabla 01-31 - Combinacin
1.4.6.3. Clase
Especifica un nombre de clase entre comillas para el segmento que el enlazador utilizar a la hora de
ordenar los segmentos. Esta ordenacin provocar que segmentos con el mismo atributo de clase se
coloquen agrupados unos tras otros. Esta caracterstica se utiliza para conseguir que todos los segmentos
de un mismo tipo (datos, cdigo, pila) se coloquen juntos en memoria cuando se cargue el programa.
Ejemplos:
Los dos cdigos fuente completos se pueden ver en el directorio Cap2 en los archivos MundoXM1.asm y
SegtosM1.asm. Ambos ejemplos tienen, a efectos prcticos, el mismo resultado, lo veremos en el siguiente
captulo.
Es muy conveniente recordar que no se le puede dar un valor directamente a un registro de segmento, sino
que hay que utilizar un registro de intermediario, como AX en este caso. Con la sintaxis NASM y FASM
no podremos usar ASSUME, puesto que no nos permite "asumir" nada y basta con la primera parte.
Mediante las nuevas directivas de segmento de la sintaxis MASM podemos, adems hacerlo de otra
manera.
.data
msg db 'Hola, mundo!$'
...
.CODE
MOV AX, @DATA
MOV DS, AX
Para acceder a una direccin de memoria, se puede poner explcitamente el valor del segmento donde est
aunque ya lo tenga el segmento DS. Por ejemplo:
MOV AX, DS:msg
La directiva ASSUME puede ir seguida de uno o varios nombres de registros de segmento seguidos de dos
puntos y el nombre del segmento hacia el que estn apuntando. Un ejemplo sera:
ASSUME CS:Codigo, DS:Datos, SS:Pila
En caso de que se desee anular la asociacin entre un registro de segmento y un segmento, se puede
utilizar el nombre de segmento NOTHING para indicar este hecho.
ASSUME DS:Datos
ASSUME DS:NOTHING
Un detalle importante es que ASSUME es una directiva y, como tal, no genera cdigo que cargue en los
registros de segmento el valor que indica. Es, por tanto, labor del programador el iniciar los registros de
segmento de forma adecuada. Es adems imprescindible colocar al principio de todos los segmentos del
cdigo la directiva ASSUME, asociando el registro CS al segmento actual.
Codigo SEGMENT
ASSUME CS:Codigo
En el caso de programas EXE se aadir otra directiva opcional ASSUME asociando el registro SS al
segmento de pila, puesto que el propio MSDOS se encarga de inicializar los registros SS y SP al segmento
de pila definido por el programa, por lo que no habr que preocuparse por cambiarlos.
Los segmentos, adems, se pueden agrupar entre s para formar segmentos mayores mediante la directiva
GROUP que va precedida por el nombre del nuevo segmento formado por la combinacin de los
segmentos cuyos nombres se indican separados por comas a continuacin de la directiva GROUP. El
tamao conjunto de los segmentos de un grupo no debe superar los 64Kb. El nombre de este grupo puede
utilizarse como si fuese un nombre de segmento. Ya hemos visto un ejemplo anteriormente.
Recurdese que muchas de estas acciones se pueden obviar utilizando directivas simplificadas de
segmento, que son: .MODEL, .CODE, .CONST, .DATA, .DATA?, .FARDATA, .FARDATA?,
.STACK, .STARTUP, y .EXIT. La estructura de un programa en ensamblador con estas directivas vienen
ms adelante.
Cdigo por
Defecto
Datos por
Defecto
Sistema Operativo
Datos y Cdigo
combinados
Tiny
Cercano
Cercano
MS-DOS
Small
Cercano
Cercano
MS-DOS,
Windows
No
Medium
Lejano
Cercano
MS-DOS,
Windows
No
Compact
Cercano
Lejano
MS-DOS,
Windows
No
Large
Lejano
Lejano
MS-DOS,
Windows
No
Huge
Lejano
Lejano
MS-DOS,
Windows
No
Flat
Cercano
Cercano
Windows NT
El modelo SMALL soporta un segmento de datos y un segmento de cdigo. Todos los datos y
cdigos son cercanos por defecto.
El modelo LARGE soporta mltiples segmentos de datos y mltiples segmentos de cdigo. Todos
los datos y cdigos son lejanos por defecto.
El modelo HUGE soporta objetos de datos mayores que un solo segmento, pero la implementacin
de este modelo debe ser cosa del programador. Puesto que el ensamblador no porporciona soporte
directo para esta caracterstica, este modelo es equivalente al LARGE.
El modelo TINY slo es admitido por el MS-DOS. Aloja todos los datos y cdigo en el mismo
segmento que no puede sobrepasar los 64Kb de longitud, al igual que el tamao del programa
completo.
El modelo FLAT funciona exactamente igual que el modelo TINY, slo que en 32 bits, alojndose
cdigo y datos en el mismo y nico segmento de 232 = 4 gigas de tamao. Para poder utilizarlo, hay
que anteponerle al menos la directiva .386. Las direcciones y punteros son todos cercanos de 32
bits.
Descripcin
@code
@CodeSize
@CurSeg
@data
@DataSize
@fardata
@fardata?
@Model
@stack
@WordSize
Descripcin
@Cpu
Representa el texto equivalente del nmero de versin del MASM. P.e. para MASM 6.1., lo
expande a 610.
Tabla 01-34 - Smbolos de mbito
Smbolo
Descripcin
@Date
@Time
Descripcin
@FileCur
@FileName
@Line
Descripcin
@CatStr
@InStr
@SizeStr
@SubStr
1.5.1. El PSP
Realmente es una reliquia del DOS, mantenido por compatibilidad. Contiene numerosos datos que el DOS
necesita para la gestin de un programa [bin], aunque para un programador, la mayora de esta
informacin, carece de inters, aunque s hay algo de mucha utilidad con la que podremos gestionar los
parmetros de entrada en la lnea de comandos. Veamos esquemticamente la estructura del PSP:
Direccin Contenido
00h-01h
02h-03h
Direccin final de la memoria ocupada por el programa. Por ejemplo A0000 se pone como
00A0h
04h
Reservado
05h-09h
12h-15h
16h-17h
18-2Bh
Reservado
32h-33h
34h-37h
38h-4Fh
Reservado
50h-51h
52h-5Bh
Reservado
5Ch-6Bh FCB #1
6Ch-7Fh FCB #2
80h
81h-FFh
Lnea de comandos
Tabla 01-38 - Esquema del PSP
El contenido "reservado" indica que son reas no documentadas oficialmente por Microsoft, pero no tiene
la menor trascendencia.
A continuacin describimos algunas de las reas ms relevantes:
En la direccin de 00h se encuentra un comando de lenguaje mquina que llama a una funcin del
DOS para terminar el programa. Vuelve a liberar la memoria del programa y transfiere el control
mediante la ejecucin del programa al procesador de comandos o al programa que ha iniciado la
ejecucin del programa a terminar. Antes se necesitaba este comando al final de un programa
COM o EXE para terminar su ejecucin, pero actualmente se utiliza la funcin 4Ch de la
interrupcin 21h del DOS.
En la direccin 02h se encuentra un word que marca la direccin final de la memoria RAM
reservada para el programa. Si un programa necesita ms memoria RAM adicional, puede
determinar con la ayuda de este valor, si an queda espacio entre su final y el fin de la memoria
RAM reservada. Si este es el caso, puede utilizar esta memoria para sus propios fines, de lo
contrario ha de pedir memoria RAM mediante una funcin DOS.
En 2Ch tenemos el segmento donde se encuentran las variables de entorno, tales como
COMSPEC, PATH, PROMPT, etc.
La direccin 81h recoge todos los caracteres que se indicaron despus del nombre del archivo
durante la llamada desde la lnea de comandos.
La direccin del PSP en los programas COM viene determinada por la de cualquier registro de segmento
(CS=DS=ES=SS) nada ms comenzar la ejecucin del mismo. Sin embargo, en los programas de tipo
EXE slo viene determinada por DS y ES. En cualquir caso, existe una funcin del DOS para obtener la
direccin del PSP, cuyo uso recomienda el fabricante del sistema en aras de una mayor compatibilidad con
futuras versiones del sistema operativo. La funcin es la 62h y est disponible a partir del DOS 3.0.
Como ya hemos dicho, un programa COM puede tener una longitud mxima de 64 Kb (65.536 bytes), de
los que se ha de descontar la longitud del PSP (256 bytes) y al menos 1 word (2 bytes) para la pila, aunque
es recomendable un mnimo de 256 bytes.
Aunque la longitud de un programa COM nunca puede pasar los 64 Kb, el DOS siempre reserva la
memoria RAM completa para ellos, con lo que no se podra llamar a otro programa con "EXEC"; esto se
puede solucionar liberando en el programa COM la memoria que no necesita, con ayuda de una funcin
del DOS, para su utilizacin.
Cuando se pasa el control a un programa COM, todos los registros de segmento apuntan al principio del
segmento COM en la memoria, con ello, el inicio del programa COM se encuentra en la direccin de
offset 100h. El puntero de stack, SP contiene el valor FFFEh, y se encuentra al final del segmento COM
de 64 Kb y va creciendo "hacia abajo", es decir, en direccin al final del programa, y debe ser el
programador el que cuide que no se solapen, en cuyo caso probablemente el programa se colgara.
Un programa COM se puede terminar con un RET ("near return"), que provoca que el programa contine
en la direccin que est como valor superior en la pila, donde el DOS coloc un cero antes de iniciar el
programa COM, por tanto saltamos a la direccin de memoria CS:0000; pero aqu se encuentra el inicio
del PSP donde est la interrrupcin 20h, que termina la ejecucin de un programa. Sin embargo, lo ms
recomendable es terminar mediante la funcin 4Ch de la interrupcin 21h, mediante la cul podemos
pasar adems un mensaje a su invocador en el registro AL, estableciendo el valor 0 como terminacin de
programa normal.
O bien liberamos la memoria completa que el programa no necesita, donde tambin se incluye la
memoria no necesitada dentro del segmento COM, obteniendo as ms espacio para otros
programas, pero con el inconveniente de que la pila queda fuera del espacio de memoria protegido
para el programa, pues el DOS lo coloca al final del segmento de 64K del COM. Pero entonces la
pila se ha de desplazar antes de liberar la memoria al final de la memoria reservada; siendo preciso
asignarle un tamao determinado, en la mayora de los casos basta con 256 o 512 bytes.
MASM
NASM
Cdigo
Cdigo
Cdigo
[bin]
[bin]
[bin]
Resultado en pantalla
Versin MASM
En las primeras lneas ponemos un comentario explicando ligeramente de qu trata el programa,
quin es su autor y cul es su actual versin. Obsrvese que los comentarios en ensamblador
comienzan con un punto y coma.
En la lnea 9 definimos un segmento de cdigo que llamaremos "codigo".
En la lnea 10 le decimos al compilador que asuma que todos los segmentos posibles del programa
tan slo estn en uno que es el que hemos definido antes "codigo".
En la lnea 11 provocamos que el compilador salte los primeros 100h bytes para dejar espacio al
PSP.
Tenemos que sealar el comienzo del programa. Eso lo hacemos en la lnea 12 con la etiqueta
"Inicio:" (las etiquetas se marcan con dos puntos). Adems con "jmp entrada" indicamos que se
salte las siguientes lneas hasta el punto de memoria indicado por entrada. Esto es as porque las
lneas que hay en medio no son ejecutables, puesto que son datos.
Las siguientes lneas estn reservadas para introducir datos.
En la lnea 16 definimos el procedimiento entrada con "entrada proc", es el principal del programa;
similar al "main" del lenguaje c. Podramos llamarle de cualquier otra manera, no slo entrada. En
la lnea 23 indicamos el fin de este procedimiento con "entrada endp". El nombre ha de ser el
mismo que el que definimos en la lnea 16. Dentro de este procedimiento es donde vamos a definir
todo lo que va a hacer el programa, y al final de ste es donde le indicamos al compilador que
limpie toda la memoria de este programa y vuelva al DOS.
En la lnea 21 con la instruccin "mov ax, 4c00h" indicamos que "mueva" al registro AX el valor
4C00h o mejor dicho que el registro AX tome ese valor. Pero debera leerse como que el byte
superior de AX, AH tome el valor 4Ch y el byte inferior, AL el valor 00. Esto es as porque en AH
indicamos la funcin que va a realizar la interrupcin 21h del DOS, en este caso finalizacin del
programa, limpieza de memoria y regreso al DOS y en AL sealamos con qu tipo de error ha
finalizado el programa, siendo un cero por defecto que indica sin ningn error.
En la lnea 22 tenemos la instruccin "int 21h", que pide que se ejecute la interupcin 21h del
DOS.
En estas dos lneas tenemos la interrupcin que devuelve la ejecucin al DOS. La interrupcin 21h
del DOS tiene muchas funciones, la que aqu utilizamos la indicamos en el registro AH, es la
nmero 4Ch, que devuelve la ejecucin al DOS. El valor que se mete en AL es opcional y sirve
para indicar si el programa ha tenido alguna malfuncin o no, el valor cero indica que todo ha ido
bien.
En la lnea 24 indicamos el fin del segmento codigo con "codigo ends".
Antes del procedimiento de entrada podramos definir ms procedimientos o macros, ya veremos
cmo.
En la lnea 25 le indicamos al compilador que termina el programa desde donde le dijimos que
empezaba en la lnea 5 con la etiqueta Inicio. Para ello utilizamos "end Inicio".
Muy bien, ya sabemos cmo es la estructura de un programa COM. Ahora vamos a compilarlo.
Para ello abrimos una ventana del emulador del MS-DOS, a no ser que ya trabajes directamente
desde el MS-DOS puro y duro. En el primer caso est en "Inicio->Todos los programas>Accesorios->Smbolo del sistema" en Windows XP. Ahora debes cambiarte al directorio donde
est nuestro cdigo fuente. Utiliza para ello la orden "CD nombre_camino". En mi caso utilizara
"CD c:\Trabajo\AOE\Codigos\Cap01". Una buena idea sera indicarle al smbolo del sistema que
se abra siempre en nuestro directorio. Para ello sitate con el cursor del ratn donde ya te he dicho
que est y pulsa el botn derecho, se te abrir una ventana, donde puedes elegir sus propiedades en
la parte inferior.
ml es el nombre del compilador de Microsoft de la versin 6.13, que adems se encarga de llamar
al linkador. "/AT" es una variante que le indica al compilador que produzca un archivo de tipo
COM, pero cuidado!, tiene que ir en maysculas. Y "EsqComM1.asm" es el nombre del programa
que se va a compilar, es necesario indicar tambin la extensin.
O bien, si tienes el ensamblador de Borland Turbo Assembler, lo puedes compilar as:
>tasm EsqComM1 [INTRO]
>tlink /t EsqComM1 [INTRO]
Con tasm se ensambla a un archivo objeto. Tlink es el linkador de Borland y "/t" le indica que
produzca un archivo COM.
Ahora ya puedes ejecutar el programa
>EsqComM1 [INTRO]
Vers que no produce ningn resultado porque el programa no hace nada salvo salir al DOS. Pero
nos sirve para saber que lo hemos hecho todo bien, pues el compilador no ha dado ningn mensaje
de error.
Esta es la pantalla de lo que me sale a m:
Versin NASM
En la lnea 1 tenemos org 100h , que sera equivalente a resb 100h , que ya sabemos que deja
espacio para el PSP.
Una diferencia importante con la sintaxis de Microsoft es que NASM no permite "asumir" nada,
hay que definirlo explcitamente.
Seguidamente definimos varias secciones:
o section .text para el cdigo.
o Section .data para los datos.
o Section .bss para los datos no inicializados.
El resto es bien conocido.
Para ensamblar dicho cdigo hacemos:
>nasmw -fbin EsqComN1.asm -o EsqComN1.com
Versin FASM
Con use16 le decimos al compilador que genere cdigo de 16 bits.
En el siguiente captulo haremos el famoso "Hola mundo", donde ya veremos un programa que hace algo.
Si vemos este programa con un editor hexadecimal, yo uso el FRHED, observaramos algo como:
Se puede observar en el bloque hexadecimal del cdigo desensamblado cmo coincide con lo que nos
indicaba el editor hexadecimal.
La utilidad DEBUG viene explicada en el apndice C. Podemos decir que el comando "u" es para
desensamblar el cdigo del programa ESQCOMM1.COM. De todas estas lneas las que nos interesan son
las tres primeras, las siguientes son desensamblado de las siguientes posiciones de memoria al programa.
Podemos observar que el desensamblado ha sido excelente.
El cdigo mquina en hexadecimal EB00 equivale a JMP 0102, que significa saltar a la posicin de
memoria 0102, que es la lnea siguiente. B8004C equivale a MOV AX, 4C00 y CD21 a INT 21.
Aqu est todo nuestro programa. Lo nico que hace es devolver la ejecucin al sistema operativo.
Vamos a dar a continuacin los otros dos esqueletos posibles para construir un archivo COM con MASM:
EsqCmM1b
EsqComM2
EsqComM3
Cdigo
Cdigo
Cdigo
[bin]
[bin]
[bin]
Resultado en pantalla
EsqCmM1b.asm
Ya hemos dicho que los archivos COM no usan diferentes segmentos puesto que todo est dentro
del mismo y que tampoco se define una pila puesto que es el propio DOS el que se encarga de
definirsela al final del programa. Sin embargo vemos en esta estructura que se definen diferentes
segmentos y adems una pila. Pero todo esto es virtual porque al final todo ello se engloba dentro
del mismo segmento llamado grupo mediante la directiva de la lnea 4:
grupo group codigo, datos, pila
Le indicamos al ensamblador que agrupe todos estos segmentos en uno solo: grupo.
Y luego, en la siguiente lnea le decimos que asuma que todos los registros de segmento apunten a
nuestro segmento grupo.
Tambin vemos como diferencia que el ttulo del programa lo especificamos con la etiqueta
"TITLE", esto es exactamente igual a utilizar punto y coma, pero es ms vistoso y legible.
EsqComM2.asm
Esta estructura es semejante a la primera pero con unas directivas simplificadas llamadas "de
segmento".
.model tiny indica al compilador que el modelo de datos que vamos a usar va a ser el ms pequeo
de todos, apropiado para archivos COM.
.code indica que aqu empieza el segmento de cdigo y termina donde empieza el siguiente.
.STARTUP es una directiva que sirve para inicializar los segmentos.
.EXIT es equivalente a hacer un mov ax, 4C00h; int 21h.
El resto de las sentencias ya las hemos estudiado. Estas estructuras no son rgidas, se pueden usar
una mezcla de ellas. Por ejemplo:
EsqComM3.asm
Podemos ver la mezcla de sintaxis clsica con simplificada.
No se indica la direccin del cdigo de nuestro comando, sino la direccin del segmento siguiente.
Evidentemente esto no se hace en un archivo COM puesto que como todo est dentro de un rango de 64K
(el mismo segmento), no es necesario.
Veamos la estructura de una cabecera de un archivo EXE:
Direccin Contenido
Tipo
00h-01h
1 Word
02h-03h
1 Word
04h-05h
1 Word
06h-07h
1 Word
08h-09h
1 Word
1 Word
1 Word
0Eh-0Fh
1 Word
10h-11h
1 Word
12h-13h
1 Word
14h-15h
1 Word
16h-17h
1 Word
18h-19h
1 Word
1 Word
1Ch-
Memoria de buffer
Variable
+??
Variable
+??
Variable
EsqExeM2
EsqExeM3
EsqExeN1
EsqExeF1
Cdigo
Cdigo
Cdigo
Cdigo
Cdigo
[bin]
[bin]
[bin]
[bin]
[bin]
Resultado en pantalla
EsqExeM1.asm
En las primeras lneas tenemos una explicacin somera de lo que trata el programa, del autor y de
la versin.
En la lnea 9 definimos el segmento de pila. Es necesario poner 'stack' para compilarlo con el
TASM. Definimos una pila de 30h palabras de longitud. Esto se hace con la instruccin "dw 30h
dup (?)". dw indica que estamos reservando espacio para palabras y 30h dup (?) indica que
repetimos 30h veces un valor indeterminado. La interrogacion indica indeterminado, dup indica
repetir y 30h el nmero de veces que se repite.
En la lnea 13 definimos el segmento de datos
En la lnea 17 definimos el segmento de cdigo.
En la lnea 18 hacemos corresponder a cada registro de segmento con su valor apropiado.
En la lnea 21 definimos el procedimiento principal del programa, seguidamente vendrn las
instrucciones de ste y luego la salida al DOS. Tanto despus como antes de este procedimiento
podemos definir otros procedimientos y macros.
En las lneas 29 y 30 terminamos con el segmento de cdigo y con el programa, respectivamente.
Para compilar este archivo utilizando MASM:
> ml EsqExeM1.asm
EsqExeM2.asm
Es la versin con directivas de segmento
EsqExeM3.asm
Mezclamos directivas de segmento con clsicas.
En esta ocasin hemos utilizado la directiva "Comment" para comentar varias lneas de cdigo. La
sintaxis es Comment y un carcter ASCII tras un espacio en blanco, es conveniente que este
carcter sea lo ms raro posible para que las lneas que queramos comentar no lo incluyan. Las
lneas comentadas terminan donde vuelve a aparecer este carcter; es un buen hbito de
programacin poner EndComment antes de l porque es ms visible e indica muy claramente cul
es el cometido del segundo carcter, si bien en s mismo no produce ningn efecto y adems est
comentado tambin. Lo dems est suficientemente claro.
EsqExeN1.asm
La nica diferencia existente aqu con los otros esqueletos vistos es que se indica dnde empiezan
los segmentos pero no donde terminan, pues esto ocurre donde empieza el siguiente segmento.
En la lnea 11 tenemos resb 256 que equivale al cdigo MASM "db 256 dup (?)".
Despus de definir el segmento de pila definimos una etiqueta "InicioPila:" que est situada en la
cima de la pila y nos sirve para indicar donde se va a situar el registro SP.
Finalmente, la directiva "..start:" le indica al compilador NASM que es aqu donde empieza el
programa y no hace falta indicarle dnde termina puesto que es al final del segmento de cdigo.
Para compilar el programa haremos lo siguiente:
>nasmw -fobj EsqExeN1.asm
>alink -oEXE EsqExeN1.obj
Alink es un linkador gratuito y necesitamos que est tambin dentro del PATH.
EsqExeF1.asm
Empezamos con FORMAT MZ, que indica al compilador que va a generar un .EXE.
Para ensamblar dicho cdigo usaremos uno de estos dos mtodos, el ms sencillo es el primero:
o Compilarlo directamente desde el editor que trae el paquete FASM.
o
Vamos a desgranar la estructura de uno de estos esqueletos EXE, para lo cul vamos a utilizar el
compilador NASM, por ejemplo, y cambiaremos ligeramente nuestra definicin de la pila, para que luego
podamos ver ms claramente dnde est situada. Para ello hemos creado el archivo EjPilaN1.exe. Lo
compilamos como ya sabemos hacer y vemos la estructura hexadecimal del fichero [bin] resultante.
Tambin podemos ver claramente las etiquetas con las que definimos la pila y que ahora nos muestran sta
muy visualmente.
Veamos cmo queda en modo de ejecucin con la herramienta debug:
C:\Trabajo\AOE\Codigos\Cap01>debug EjPilaN1.exe
-d 100
0D18:0100 3C 2D 20 41 71 75 69 20-65 6D 70 69 65
0D18:0110 6C 61 20 70 69 6C 61 20-79 20 20 61 71
0D18:0120 74 65 72 6D 69 6E 61 20-00 00 00 00 00
0D18:0130 B8 28 0D 8E D0 BC 2A 00-B8 28 0D 8E D8
0D18:0140 21 C4 12 F3 A4 1F 03 E2-5F 5E 5A 59 5B
0D18:0150 12 2E 8E 16 40 05 8B E0-A1 04 15 C3 59
0D18:0160 14 8B D1 C1 E1 04 C1 EA-0C E8 61 1F 73
0D18:0170 14 C1 E9 04 8A C2 C0 E0-04 0A E8 C1 EA
-q
7A
75
00
B4
89
8B
20
04
61
69
00
4C
26
0E
A3
74
20
20
00
CD
C2
EE
D4
03
Vamos a utilizar aqu el editor hexadecimal gratuto "HexIT" que posee una opcin que nos va a ofrecer
una informacin muy valiosa respecto a la cabecera de nuestro archivo "EXE":
En "Run-> Set Runtime Arguments..." del CodeView podemos establecer cul va a ser el agumento de
lnea de comandos para nuestro programa, yo he elegido "miArgumento"; no es original, pero es muy
visible.
Los dos primeros bytes contienen una llamada a la interrupcin 20h: "CD 20", que produce un retorno al
DOS.
En el byte 80h nos indica el nmero de bytes que hemos ingresado por lnea de comandos sin contar el
retorno de carro: "0C", es decir, 12 en decimal.
NASM es sensible a las letras en maysculas y minsculas, mientras que MASM slo lo es usando
la opcin /Cp. Esto quiere decir que las variables miVar y MiVAR no son la misma en NASM,
pero s en MASM sin la opcin correspondiente.
Seccin sin inicializar. Nasm permite generar una seccin de variables sin inicializar con la
etiqueta .bss, eso significa que reserva ese espacio de memoria, pero no lo ocupa, con lo que el
[bin] resultante es de tamao inferior. Las variables sin inicializar en MASM s ocupan espacio.
Mientras MASM usa "stack db 64 dup (?)", NASM usa "stack resb 64", como intentando que se
lea "reserva 64 bytes de memoria".
NASM no usa etiquetas especiales para definir procedimientos, sino que quedan identificados por
una etiqueta a la que se salta.
Las etiquetas definidas por NASM dentro de un procedimiento nunca son locales a no ser que se
indique explcitamente anteponindoles un punto, mientras que MASM siempre las define como
locales dentro de un procedimiento a no ser que indiquemos explcitamente que no lo son. Al no
ser locales en cada procedimiento implica que no podremos usar etiquetas con el mismo nombre en
diferentes procedimientos
NASM no "ASSUME", por simplicidad, nunca guarda los valores de los registros de segmento y
nunca generar un prefijo dominante de segmento.
NASM no soporta Modelos de Memoria. Tampoco tiene directivas para respaldar los diferentes
modelos de memoria. El programador debe encargarse de invocar a una funcin con una llamada
cercana o una lejana y tambin volver de ella con un RETN (cercano) o un RETF (lejano),
admitiendo RET como RETN.
Diferencias con la coma flotante. NASM usa diferentes nombres de registro del coprocesador que
el que usa MASM. NASM usa st0, st1,... frente a st(0), st(1),... del MASM.
NASM requite corchetes para todas las referencias de memoria. Por ejemplo el siguiente cdigo:
uno
dos
equ 1
dw 2
;
;
;
;
AX
AX
AX
AX
=
=
=
=
El parmetro PTR slo existe en MASM, por ejemplo, las siguientes sentencias son equivalentes
en MASM y NASM:
dos
MOV
MOV
Los segmentos de memoria deben estar dentro del corchete, por ejemplo:
MOV
MOV
dw 2
AX, WORD PTR [dos]
AX, WORD [dos]
AX, ES:[BX]
AX, [ES:BX]
; AX = 2 en MASM
; AX = 2 en NASM
; Correcto en MASM
; Correcto en NASM
Nasm reserva espacio con la directiva RESB, Fasm lo hace con RB o tambin con ?, por ejemplo:
Var1
Var2
DB ?
RB 1
En el coprocesador matemtico, NASM define el primer registro con ST0, mientras que FASM lo
hace con ST
Fasm no define espacios especiales con etiquetas como ".bss". En el caso de variables sin
inicializar lo hace como ya hemos indicado anteriormente.