Segundo capítulo del tutorcillo. Distribuido como whisky-ware por la BBS Public Enemy, circa 1996. El texto es el original, sin tocar.
░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
░▒▓ Tutorcillo chencho de ASM ▓▒░
░▒▓ Segundo Capitulo ▓▒░
░▒▓ Whisky-whare del Sami 3;*)▓▒░
░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
-*-
En este capitulo ya aprendes
a ir programando y demas. Supongo
que hara falta otro capitulillo
mas (o igual hasta 2)... pero
ahora estoy un poco liado por
lo que ir "entrenando" con este
y el anterior... Si hay dudas...
ya sabes, estoy por Public Enemy.
-*-
( aun no se para que tengo el
warlock) };)
░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒░ ░▒▓ ▓▒░ ░▒▓ Tutorial de ASM ▓▒░ ░▒▓ ▓▒░ ░▒▓ (II de momento) ▓▒░ ░▒▓ ▓▒░ ░▒▓ Sami 1.996 (Manolo Buitre por aquello de mantener anonimato paterno) ▓▒░ ░▒▓ ▓▒░ ░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒░
Este es el segundo capitulo (y como sea como el anterior en 3 capitulos nos cepillamos el curso ;-)... espero que el anterior os haya ido igual que a mi el verano. Voy a ver que dejamos pendiente del otro dia........
01 — Comenzando con experiencias y pasando de la teoria... -;)
Bueno... pasamos a programar... ¿que te gustaria hacer?... ¡ lo estoy oyendo ! ¿un motor 3D?... bien... eso creo que es lo que en Basic se llama PRINT -3;)... pero antes un pelin mas de teoria (que en realidad es practica, vamos). Antes de seguir, ¿recuerdas lo de los opcodes?... si no lo recuerdas repapalos, porque aqui voy un poco mas alla:
; Compila a partir de aqui
; Segundo programa de XXXXXX
.MODEL MediuM ; En este caso mejor un Tiny
.DATA ; Sobra (pero sigue leyendo!)
.CODE
mov ah,4Ch ; Salida al dOS con "errorlevel"
int 21h ; (es un servicio de interrupcion)
END
Venga, a que sabes lo que hace el programa de ahi arriba?... pues ahora vayamos con una orden del *compilador* (no del procesador)... en realidad son varias pero todas hacen cosas muy parecidas:
Te presento a DB, DW, DD, DQ y DT (aunque hay alguna mas, es ==)
Antes de que te cagues en algun santo, te aviso que ya me cague yo, asi que a callar... ¿Que que hace DB?... Mira:
.MODEL MediuM ; Como tengo datos y codigo mejor el medium
.DATA ; para este ejemplo no sobra, eh! 3;)
Mi_letra DB 'A' ; Mete el codigo ASCII de A
Mi_letra2 DB 65 ; (que es este)
Entero DW 1234h ; definimos 16bits
Mi_letra3 DB 41h
.CODE
mov al,byte ptr Mi_letra ; Mete en al 41h
mov bl,byte ptr Mi_letra2 ; Mete en bl 41h
mov cl,byte ptr Mi_letra3 ; Mete en cl 41h
mov ah,4Ch ; Salida al dOS con "errorlevel"
int 21h ; (es un servicio de interrupcion)
END
Vale tio! no te pongas asi... mal ejemplo, ya lo se... jugaremos un poco con el para que lo cojas. Primero ten tu tablita de ASCII al lado ¿ya?... sigamos...
Empezemos analizando el programa:
- ".MODEL MediuM"
Quiero un segmentiko de datos y otro de codigo.
- ".DATA"
Lo que haya hasta ".CODE" sera mi segmento de datos,
donde metere los datos que quiera (hasta 64 Kb)
- "Mi_letra DB 'A'"
Asigna una variable de 1 byte que contenga el codigo
ASCII de la letra "A" (mayuscula), el cual es 65 en decimal
o 41h (que es el mismo, claro). Las siguentes asignaciones
con DB son iguales. Si pusieramos DW, "Definieriamos un Word",
usease un entero de 16 bits, con DD un doble etc.
Analicemos esto mas a fondo ya que es muuuuyyyyyy importante:
El primer DB se pondra al principio del segmento de datos,
el segundo DB en el segundo byte de este segmento, al poner
el DW en el tercero y cuarto byte quedara esto:
3 4 <== offset dentro del segmento de datos
-------
34h 12h
No me he confundido... sino que el almacenamiento de word,
dobles y demas se hace de manera invertida, es decir, la
parte mas "estupida" delante, y la parte alta del valor
(MSB me parece que le llaman en ingles, por aquello del
Most Significant Byte) detras. Es algo muuuyyyy a tener en
cuenta si por ejemplo has definido algo con un DW y luego
quieres leer solo un byte de esa posicion de memoria.
- "mov al,byte ptr Mi_letra ; Mete en al 41h"
Bueno, por si lo recalco poco, el ";" ese es un comentario.
y luego vamos con eso que pone de "byte ptr"... lo que hace
es decir que meta un byte de la posicion de memoria "Mi_letra"
Si le dijeramos un "mov ax,word ptr Mi_letra", en ax
tendriamos este byte y el siguiente. (es sencillo, ¿no?)...
Bueno, quiza esto sea una tonteria ya que si pones "mov al,XXX"
se sobreentiende (por ser AL de 8 bits), que solo quieres coger
un byte. De hecho CREO que a los compiladores modernos no les
hace falta esto (yo como voy con mi viejiiiisimo TASM pues
prefiero ponerlo por clarificar).
¿donde estabamos?... ah... pues nada... que el programa ya ha acabado. Como ejercicio de este mini-tema... te pillas el Turbo Debugger y cargas este programa (.EXE). Para ello tendras que crear el .ASM con un editor de textos normal, luego pasarselo por el TASM ("TASM mi_prog.asm") y por ultimo linkarlo ("TLINK mi_prog.obj"). Los puntos de ruptura en el TD se ponen con F2, con F9 se ejecuta el programa hasta el final y con F7 vas "traceando" paso a paso lo que va haciendo el bicho. Como consejos... juega a ver la memoria, o tu programa cargado en memoria (en forma de opcodes) etc. El TD (turbo debugger) sera una de las herramientas mas utiles que vas a tener (bueno, la mejor) por lo que al principio no sabras ni lo que es, pero cuando juegues un poco con el ya veras que sencillo. :)
Otro ejercicio (un poco estupido tal vez) es coger un desensamblador y crear otro ASM (pero partiendo del ejecutable)... esto te vale para que sepas lo que hacen las directivas esas de .MODEL y demas, aparte de que te daras cuenta del monton de maneras que tienes de poner una cosa en ASM.
Aunque en el anterior capitulo te engañe diciendo que no habria mas teoria (creo que te ido engañando todo el "camino" ;)... en este ya no te va a "entrar" mas (que no quiere decir que no vaya a haber mas, pero sera mas "discreta")... en este capitulo tengo previsto que juegues un poco con el 8086 usandolo para hacer calculos sencillos etc. Usaras algunas de las interrupciones mas utiles y demas... asi que adelante :)
Vamos a empezar sacando un texto a pantalla:
.MODEL MediuM ; 64Kb de datos y 64Kb de codigo
.DATA ; Segmento de datos
Cadena DB "Esto esta en pantalla$"
; La cadena va entre comillas, y si usas
; el DOS para imprimir una cadena (cadena
; es una tira de bytes), el fin de cadena
; se señala con un "$".
.CODE ; Segmento de codigo
mov ax,@DATA ; Configura el DS => @DATA es el segmento
mov ds,ax ; de datos que pones con la directiva ".DATA"
; pero DS no es accesible directamante (como
; los demas registros de segmento) y por eso
; metemos el segmento en AX.
mov dx,offset Cadena ; El servicio 9 de los servicios del DOS
mov ah,9 ; (int 21h) imprime una cadena hasta que
int 21h ; encuentra un "$".. es decir... un 36.
; Para indicarle que cadena quieres sacar
; por la pantalla, el segmento de donde
; esta la cadena se mete en DS, y el offset
; en DX. Luego se llama a la interrupcion 21h.
mov ah,4Ch ; Acaba el programa
int 21h
END ; Fin del programa
Este es el "listing" del programa de arriba (se hace con: TASM uu.asm /la /zi ... y se genera el uu.lst):
1 0000 .MODEL MediuM
2 0000 .DATA
4 0000 45 73 74 6F 20 65 73+ Cadena DB "Esto esta en pantalla$"
7 24
13 0016 .CODE
15 0000 B8 0000s mov ax,@DATA
16 0003 8E D8 mov ds,ax
21 0005 BA 0000r mov dx,offset Cadena
22 0008 B4 09 mov ah,9
23 000A CD 21 int 21h
29 000C B4 4C mov ah,4Ch
30 000E CD 21 int 21h
32 END
02 — Plantillas para tus programas mas simples
PARA HACER UN .COM
Codigo Segment
assume CS:Codigo, DS:Codigo
org 100h
; AQUI VA TU CODIGO Y TUS DATOS.
Comienzo:
mov ax,4C00h ; Salida al dos con errorlevel
int 21h
Codigo EndS
End Comienzo
Compilar: Tasm mifich.asm
Linkar: Tlink/t mifich.obj
PARA HACER UN .EXE
.MODEL medium
.386
.DATA
ejemplo DB "Hola$"
.CODE
mov ax,4C00h ; Salida al dos con errorlevel
int 21h
.END
Compilar: Tasm mifich.asm
Linkar: Tlink/3 mifich.obj
PARA LAS .QLB (para Quick Basic 4.x)
.MODEL medium,Basic
.386
.DATA
ejemplo DB "Hola$"
.CODE
Public MiSubrutina
MiSubrutina Proc Far, parametro:word
MOV BX,parametro
MOV AX,[BX]
RET
MiSubrutina EndP
.END
Compilar: Tasm mifich.asm
Linkar en LIB: Lib milib.lib +mifich.obj
Crear QLB: Link/QU milib.lib, milib.qlb,nul,bqlb45.lib
03 — Las puertas logicas
Existen fisica y logicamente... forman la base mas simple del ordenador, desde las memorias hasta el propio procesador, por lo que te podras imaginar la importancia que tienen.
Las instrucciones del procesador son: AND, OR, XOR y NOT
Al principio te pareceran que no valen para nada, que no te acuerdas y que en caso de que te acuerdes no sabes donde usarlas, pero eso va junto con la practica 3;D
NOT ==> 0 - 1 / 1 - 0 — Niega: si tienes un 1 te da un 0 y viceversa:
.MODEL tiny
.CODE
mov ax,11111111b ; o lo que es lo mismo 00FFh
not ax ; En AL tendremos todo a 0 y en AH todo a 1
mov ah,4Ch ; Salida al DOS
int 21h
END
Lo mejor con las puertas es que tu mismo llegues a tus conclusiones, ya que yo de primeras me las aprendi, de segundas las olvide, de terceras saque mis conclusiones y por fin las use ;DDDDD. Pruebalas con el Turbo Debugger, y si no lo tienes, ya sabes... };)
OR ==> 0-0=0 / 0-1=1 / 1-0=1 / 1-1=1:
mov al,00010001b
or al,00000010b
El bit numero 1 se pondra a 1 pero sin cambiar los demas
bits. El resultado, como en todas las instrucciones de ASM,
se ponen en el primer operando, es decir, en este caso, AL.
XOR ==> si son iguales da 0, si son distintas da 1. Por eso se usa: "xor ax,ax" para borrar AX... puesto como AX y AX son iguales (no te jode...)...
AND ==> Ambos a 1 si quieres 1. Por eso se usa para hacer comparaciones de bit en bit:
mov al,01001001b
and al,00000001b ; Esto dara 1... :)
mov al,00000000b
and al,00000001b ; Y esto dara 0... :)
En ensamblador tambien existe otra AND. Se diferencia de esta en que TEST (que asi se llama esta nueva instruccion), no guarda el resultado en ningun sitio... y puesto que te puedes preguntar que para que sirve pues (a que siiiiii... ..... ;DDD)... vayamos a MAS PRACTICA!!!
04 — Saltos y demas (lo que se llaman bifurcaciones)
Hasta ahora los poquitos programas que hemos hecho han sido lineales. Comenzaban en un principio. Y acababan en un final. Pero claro... pocos programas pueden ser lineales y deben hacer una cosa u otra (segun unas condiciones, claro).
Dejemonos de rollos que tengo que merendar y son ya las 7:
.MODEL medium
.DATA
h1 DB "Pues el bit 0 estaba puesto a 1$"
h2 DB "Pues el bit 0 no estaba puesto a 1$"
variable DB 00h
.CODE
mov ax,@data ; Prepara DS con @DATA
mov ds,ax
mov byte ptr variable,00110101b ; mete esto en "variable"
mov al,byte ptr variable ; en al esta 00110101b
test al,00000001b ; una AND con un 1
jz no_uno ; si el resultado da 0...
; ...salta a la etiqueta
mov ah,9 ; no_uno (Jump if Zero)
mov dx,offset h1 ; ^ ^ ==> JZ
int 21h ; ... y si no es 0, seguir
jmp final ; ... y saltar a final
no_uno:
mov ah,9
mov dx,offset h2
int 21h
final:
mov ah,4ch ; Sale al DOS
int 21h
END
Veamos la explicacion de este "fenomeno"... resulta que donde pone "jmp final", cuando se esta ejecutando esta instruccion, el CS:IP (ya sabras por fin que es esto)... pues digamos que es 6000:0020 (inventao, por supuesto). "Final" es un simbolo, una etiqueta..."algo" que marca una posicion de memoria (que es la de "mov ah,4ch")... por lo que si ponemos que salte a Final (jmp final)... saltara a la posicion de memoria donde este "mov ah,4ch"... existen tres tipos de saltos...
el short: que permite un salto *** RELATIVO *** (a donde estes
en ese momento) de 8 bits... es decir, entre -128 y
+127. Normalmente no te tienes que preocupar del tipo
de salto, porque lo suele poner el compilador gracias
a las directivas. Ocupa el opcode de JMP + 1 byte.
el near : un salto intrasegmental, dentro del mismo segmento
de codigo. Por lo que solo modifica el IP. Solo ocupa
por tanto un byte mas que el anterior.
el far : un salto intersegmental... entre segmentos.. modifica
el CS:IP, por lo que ocupa 2 bytes mas que el anterior.
Es importante saber que tipo de salto usar puesto que contra mas "lejano" sea, mas lento es el salto, y mas espacio ocupa en memoria (la instruccion, por supuesto).
05 — Inciso especial: los flags ;)
Los flags es otro registro de 16...... siiiiii.... oooootroooo 3:). ... pero este es especial... no se puede poner "mov ax,flags" ni nada asi. Esto son las flags (a ver si no me equivoco demasiao ;):
15 0 ==> Nº de bit
* * * * | * * * * | * * * * | * * * *
OF DF IF TF SF ZF AF PF CF
Tranquilooooooooo.... que no es nada!!!
Si esto lo lees por primera vez, no te preocupes si no entiendes nada, este inciso esta aqui por referencia, no por explicacion ;)... la explicacion se ve muuuucho mejor en la practica que en la teoria. Cada bit de estos sirven para indicar una cosa u la otra (por eso son bits). Aqui va la lista... si un bit esta a 1:
CF: "carry flag" ==> el acarreo al sumar
OF: "OverFlow" ==> cuando te pasas y no cabe en 8 o 16 bits un valor
ZF: "Zero Flag" ==> (este es lo del JZ)... 1 si una comparacion
es cierta.
SF: "¿Sign Flag?"==> bla,bla,bla
AF: "¿?" ==> lo mismo que el carry pero cuando curras en BCD
( ya veras que es eso, por ahora sigue dando
saltitos pequeños ;)
DF: "Direction flag" ==> indica si las cadenas se almacenan hacia
arriba o hacia abajo. (piensa en ello)
IF: si las interrupciones estan activadas (o no, claro)
TF: el "trapping"... para ejecutar programas "paso a paso"... esta
pijorra la usa el Turbo Debugger por ejemplo, cuando estas dandole
al F7 y F8.
Hay mas en procesadores superiores al 8086, peeeroo.... el Samy tiene tanta informacion de PC superiores al 8086 como vosotros... por lo que cuando pasemos del 8086 vereis como mis "conocimientos" ("aunque mi mami dice que no tengo") se van degradando 3;(
06 — Saltos y demas (lo que se llaman bifurcaciones) ][
Y como no hay 2 sin una (y me juego lo que quieras a que tengo que hacer el ][I... y seguro que gano claro X-D)... aqui van MAS SALTOS!!! Pues como antes solo te enseñao el salto no-condicional, ese que salta sin condicion (jmp) y el JZ (si el resultado es 0)... pues te habras mosqueao, pero aqui vienen mas:
JA : jump if above => salta si es mas grande JAE : jump if above or equal => si mayor o igual JB : (ah, perroooo) jump if below => si es menor JBE : jump if below or equal => o menor o igual JE : jump if equal => salta si es igual Y ahora los contrarios a estos: JNA : si NO es mas grande JNB : si no es mas pequeño ... bueno, todos negaos, pero con la N despues de la J ;)
Seguiremoooooos... hay muchiiisimos mas CX-DDDDDDDDDD, pero antes entrenemos estos un poco puesto que son los mas sencillos y los mas usados:
.MODEL medium
.DATA
h1 DB "es igual a 1$"
h2 DB "No es igual a 1$"
.CODE
mov ax,@data ; Prepara DS con @DATA
mov ds,ax
mov al,1
cmp al,1 ; compara al con 1
jne no_uno ; y SEGUIDAMENTE... si no es igual
; salta a no_uno
; INCISO: "CMP" es una instruccion
; del procesador, no es el test
; de antes (que tambien es del proce-
; sador). Y casi siempre lleva el
; Jxxx detras.
mov ah,9
mov dx,offset h1
int 21h
jmp final
no_uno:
mov ah,9
mov dx,offset h2
int 21h
final:
mov ah,4ch ; Sale al DOS
int 21h
END
Lo siento por no poner comentarios pero es que es igual que el anterior :) Los demas tipos de estos saltos, ya sabeis, practicarlos 3:D
La semana que viene seguiremos con otros tipos de saltos, subrutinas y demas. Crearemos nuestra primera interrupcion etc. Pero os dejo deberes (X-DDDDDDDDDD).... probar todo lo que hemos dado hasta ahora, sin ningun miedo porque no os podeis cargar nada (mientras no toques la INT 13h, que es la de disco)... segundo: conseguiros de una vez la lista de interrupciones, que esta en Public Enemy (53-18-07)... la de Ralf Brown mismo. Probar cosillas con ellas, que se aprende mucho y luego os cogeis la lista de instrucciones del procesador (y si no la conseguis pues me la pedis a mi). Y creo que no se me olvida nada mas... que os cuideis y feliz (va con segundas, por supuesto) fin de semana 3:*DDDD...... ¡¡¡FAFAN PAGATE ALGO!!!
PD: Documento guiski-ware, share-whiski o como tu quieras }:*D~~