Únete
a la comunidad
Inscríbete
Haz una pregunta »

Ejercicio de ensamblador para x86: invertir cadenas

Mayo 2013




Introducción


Este pequeño ejercicio de lenguaje ensamblador es para la arquitectura x86 (Procesadores Intel y Amd 32 bits) y utiliza la sintaxis de Nasm, un ensamblador libre, gratuito y que puede ser utilizado en diferentes plataformas como Windows o Linux.
Además, las funciones externas utilizadas provienen de la biblioteca de C estándar.

Por lo tanto, no tendrás problemas con tu equipo para realizar este ejercicio: éste no depende del sistema operativo utilizado. Únicamente depende de la arquitectura x86.

Nota: Para utilizar nasm con el propósito de probar este ejercicio, puedes consultar el tutorial de uso e instalación de nasm para Windows y Linux haciendo clic aquí

Nociones tratadas en este ejercicio

  • Las funciones con parámetro de entrada
  • Los saltos
  • La pila
  • Las cadenas de caracteres

Enunciado


El objetivo es el de escribir una función en ensamblador capaz de invertir una cadena de caracteres.
Esta función deberá aceptar como parámetro de entrada un puntero hacia una cadena de caracteres e invertir esta cadena en el mismo puntero.

Esto es lo que daría esta función en C:

void invertir_cadena(char *str); //El modelo de esta función
//Ejemplo de uso:
char string[] = "Esta es la cadena a invertir";
invertir_cadena(string);
printf(string); //Mostrará "ritrevni a anedac al se atsE"


Deberás insertar este código aquí:

extern printf

section .data
	cadena db 'Invierteme! Yo te dire que programador eres!', 0x0

section .text
	global main, invertir_cadena

invertir_cadena:
		;Pon el código aquí


main:
		mov eax, cadena ;Direccion de cadena en eax
		push eax
                ;Llamado de invertir_cadena con la dirección de la cadena a invertir
		call invertir_cadena
                ;Las dos líneas siguientes son opcionales ya que la dirección 
                De la cadena (ahora invertida) siempre está en la pila. 
                mov eax, cadena; Dirección de la cadena en eax
		push eax
                ;Visualización de la cadena con printf
		call printf
		add esp, 4 ;Salimos de la función main
		mov eax, 0


Intenta resolver este ejercicio por ti mismo sin mirar las siguientes secciones. Si tienes alguna dificultad, consulta la sección que sigue (Índices), luego vuelve a intentarlo.

Para recordar

  • Un carácter ASCII estándar está codificado en un octeto. Por lo tanto, una cadena de caracteres es una serie de caracteres de 1 octeto y no de 4 como los enteros.
  • Una cadena termina con el carácter 0 (el valor 0 y no el carácter '0').
  • Únicamente se pueden apilar elementos de 2 ó 4 octetos en la pila (a menos que se trate de una constante de un octeto).

Propiedad


Probablemente sepas que la pila es una memoria cuyo acceso es del tipo Last In First Out. Lo que significa que si pones en la pila tres letras una a continuación de la otra, por ejemplo primero a luego b luego c, las recuperarás en el orden inverso: primero c luego b luego a.

Solución


Aquí una solución:
invertir_cadena:
;Inicio de la función
		push ebp
		mov ebp, esp
	
                ;Cargamos el puntero pasado como parámetro en eax
		mov eax, [ebp+8]
                ;Introducimos el carácter de fin de cadena en la pila
		push word 0

	cadena_en_pila:
                ;Vamos a apilar cada carácter de la cadena

                ;Recuperación del carácter actual
		mov bl, byte [eax]
                ;¿Es el fin de la cadena? (bl = 0 ?)
		test bl, bl
                ;Si es sí pasamos a la etapa siguiente
		jz fin_cadena_en_pila
                ;Si no apilamos el siguiente carácter 
		push bx
                ;Incrementamos el puntero en 1 para procesar el siguiente carácter 
		inc eax
                ;Pasamos al siguiente carácter 
		jmp cadena_en_pila

	fin_cadena_en_pila:
                ;Volvemos a cargar el puntero de la cadena para desapilar uno a uno cada carácter
		mov eax, [ebp + 8]

	invertir:
                ;Desapilamos el carácter actual
		pop bx
                ;Lo cargamos en el puntero de cadena
		mov byte [eax], bl
                ;Incrementamos la dirección
		inc eax
                ;¿Era el fin de la cadena? (¿el 0 que hemos apilado al inicio?)
		test bl, bl
                ;No entonces continuamos
		jnz invertir
                ;Es el fin de la cadena, indicamos el fin de la función
		leave
		ret

Explicación


Como ha sido sugerido en la sección “índices”, lo ideal es utilizar la pila. Se apilan los caracteres de la cadena y al ser desapilados se obtienen en el orden inverso.
Esto es lo que ocurre: primero apilamos 0 que será desapilado al final para indicar el fin de la cadena.
Luego, apilamos uno a uno cada carácter de la cadena pasando por bl (los 8 caracteres de peso débil de ebx) que es suficiente para un carácter. Al apilar, tomamos bx (16 bits de peso debil de ebx) que contiene a su vez bl ya que estamos obligados a apilar al menos 2 octetos.
Durante estos sucesivos apilamientos, tendremos cuidado de no apilar el carácter de fin.

En la siguiente etapa, volvemos a cargar el puntero con la dirección del inicio de la cadena. Luego, desapilamos sucesivamente cada carácter en la cadena borrando los valores antiguos. Cuando hayamos desapilado el 0 de fin de cadena, también lo insertamos en la cadena luego terminamos. Y listo!

Véase también

Comunidad de asistencia y consejos.

Exercice assembleur x86 inversion de chaîne
Exercice assembleur x86 inversion de chaîne
Por kilian el 18 de marzo de 2008
El artículo original fue escrito por kilian. Traducido por Carlos-vialfa.
Este documento intitulado « Ejercicio de ensamblador para x86: invertir cadenas » de Kioskea (es.kioskea.net) esta puesto a diposición bajo la licencia Creative Commons. Puede copiar, modificar bajo las condiciones puestas por la licencia, siempre que esta nota sea visible.
Recibe nuestro newsletter

salud.kioskea.net

Ejercicio de ensamblador x86: ocurrencia de un carácter
Ensamblador - Multiplicación por una constante