Programación en Lenguaje Ensamblador

-El Verdadero Lenguaje de las Máquinas-

Un Byte A La Vez

Como convertir un dato binario en una cadena ASCII

En mis vergonzosos tiempos de lamer en los que tenía el vicio de programar en c. Vicio que dicho sea de paso se quita al salir de la pubertad, recuerdo haber usado una función que tomaba un valor entero y retornaba una cadena ASCII. Esta función se llamaba ITOA. Sin embargo nunca llegué a usarla porque el printf() se encargaba de desplegar cualquier tipo de cadena que uno quisiera en el formato que uno quisiera. De hecho, en las contadas universidades en las que aún se enseña lenguaje C, la mayor parte del curso consiste en el manejo de Printf() y scanf(). Bueno, la verdad es que estuve hurgando en las funciones mas extrañas de la API de Windows y no encontré ninguna que hiciera nada parecido, a lo mas es posible validar las entradas de una caja de texto. Así que esta entrada versa sobre como convertir un entero de 8 bits en una cadena ASCII-Z.

La primera pregunta es ¿Porqué en hexadecimal? Porque es el modo mas sencillo de hacerlo. Mas adelante verán que es posible usar casi el mismo proceso para obtener una cadena ASCII decimal con la ayuda de la Unidad de Punto Flotante (FPU). Lo primero que hacemos es crear un arreglo de bytes donde el offset corresponda con su código ASCII. Esto es tan fácil como crear una cadena de texto:

digitos db ‘0123456789ABCDEF’,0

Luego ponemos en cero un registro de propósito general, en este caso eax con la instrucción XOR:

xor eax,eax

Cuando uno hace un XOR entre dos valores que son iguales el resultado es cero, no importa de que valor se trate. De hecho, la mayor parte de los XOR que uno encuentra en un programa se usan para inicializar registros generales. Esto es porque MOV EAX, 0 ocupa 6 bytes de memoria mientras que un XOR EAX, EAX solo 2 bytes. Mas adelante habrá una nota completa para esta instrucción.

Como el dato a convertir es tan solo de 8 bits, movemos el valor de 8 bits a la parte baja de EAX, el subregistro AL. Supongamor que en algún lugar del segmento de datos tenemos el valor a convertir:

valor_binario		db	0C8h ; este es un byte que contiene un 200 decimal

Ahora necesitamos los 4 bits mas bajos de este byte. Pero solo podemos transferir 8 bits a la vez, como lo hacemos, con una cosa llamada MASCARA AND. Con este par de instrucciones:

mov	al, 0fh
and	al, [valor_binario]

la primera instrucción pone los 4 bits mas bajos del subregistro AL en UNO. A la hora de hacer un AND con el contenido de la celda en valor_binario los únicos bits que se copiarán tal y como están serán los 4 bits mas bajos; todos los otros van a quedar en cero. El contenido de AL en este caso es un 8. Ahora convirtamos ese 8 en un 38h.

Los mas sencillos sería sumar 30h, hacer un OR AL, 30h sería mas rápido, sin embargo, dado que estamos trabajando en hexadecimal, si recibiéramos valores por arriba de 9 este proceso fallaría. así que ejecutamos la siguiente instrucción:

mov	al, [eax + digitos]

Esto es llamado por los matados direccionamiento índice mas desplazamiento. En este caso, movimos a AL el octavo byte a partir de la posición indicada por la etiqueta ‘digitos’. Para que esto funcione, todos los bits de EAX deben estar en cero menos los últimos 4. Ahora que tenemos este valor lo guardamos en el STACK con:

push eax

para los 4 bytes que nos faltan ahora movemos a AL el valor a convertir (otra vez) y lo desplazamos 4 b

bits a la derecha con este par de instrucciones:

mov	al, [valor_binario]
shr	al, 4

la instrucción SHR significa SHIFT RIGHT y empuja a los bits del primer operando hacia la derecha tantas posiciones como lo indique el segundo. En algunos CPU’s mas antiguos, era necesario escribir el 4 en el contador. La pregunta es ¿Que les sucede a los bits que ya no caben en el registro?. La respuesta es simple y macabra. ¡Desaparecen! Del mismo modo en que una persona cae cuando la empujan de la orilla de un pozo. Prensen en el registro como un puente que cruza un precipicio. Lo mismo para por la izquierda con la instrucción SHL. Ahora en AH tenemos un 0Ch. Y lo convertimos en 4Ch con:

mov	al, [eax + digitos]
push	eax

El valor ya está convertido, solo falta construir la cadena ASCII-Z. Lo primero es una posición de memoria donde la vamos a escribir. Supongamos que tenemos un arreglo de 3 bytes inicializados en 0 apuntados por la etiqueta cadena_ascii:

cadena_ascii	db	0,0,0,0,0,0,0,0

ahora necesitamos un registro que haga el papel de puntero. Usaremos EDX haciendo que este registro apunte a esos 8 ceros con:

mov	edx, cadena_ascii

Seguro se preguntarán porque usamos dos instrucciones PUSH, pues si se fijaron los grupos de 4 bits se leyeron de ‘derecha a izquierda’. Pero cuando los extraigamos del Stack con POP estos valores estarán ordenados de ‘izquierda a derecha’ así que con estas instrucciones se construye la cadena ascii:

pop	eax
mov	[edx], al
inc	edx
pop	eax
mov	[edx], al
inc	edx
mov	edx, byte 0

Los 2 primeros trios de instrucciones sacan 2 DWORDS del Stack y escribe sus 8 bits mas bajos en la posición a la que apunta EDX. En este caso, el buffer donde se guarda la cadena ASCII. La instrucción INC aumenta en una unidad el operando. En este caso edx. Al hacer esto EDX apunta al siguiente byte. La última instrucción mueve un cero inmediatamente después de la cadena para indicar el fin de esta.

Listo, hemos terminado. Si quieren jugar con este código pueden integrarlo a PEDEMO.EXE y pasar como parámetro a MessageBox cadena_ascii en lugar de message. Así podrán visualizar un byte de la memoria a la vez. Supongo que con lo dicho aquí cualquier programador mas o menos competente podría convertir a ascii un valor de 32 o 64 bits. Para los que no saben programar y por eso leen este blog pronto publicaré el código que hace esto para que lo corten y lo peguen en sus tareas escolares. Pero no esperen un programa completo que haga esto. Fin por ahora…

febrero 4, 2009 - Posted by | Uncategorized

Aún no hay comentarios.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: