Cómo invertir cadenas en ensamblador x86

Noviembre 2016

Este pequeño código en lenguaje ensamblador está hecho para las arquitecturas x86 (procesadores Intel y AMD 32 bits) y usa la sintaxis de Nasm, un ensamblador libre, gratuito y que puede ser utilizado en diferentes plataformas como Linux o Windows.

Las funciones externas utilizadas provienen de la biblioteca C estándar. Por tanto, no tendrás problemas con tu equipo al utilizar este código, ya que no depende del sistema operativo utilizado. Únicamente depende de la arquitectura x86.

Nota: para saber cómo utilizar Nasm a fin de probar este código, consulta la siguiente ficha: Cómo compilar un programa ensamblador con Nasm.


Funciones y nociones utilizadas para escribir un código que invierte cadenas

Para escribir este código se tienen en cuenta las funciones con parámetro de entrada, las instrucciones de salto, las cadenas de caracteres y las pilas.

Enunciado

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

El código en C sería:

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 el código aquí:

extern printf

section .data
cadena db '¡Inviérteme! ¡Yo te diré qué programador eres!', 0x0

section .text
global main, invertir_cadena

invertir_cadena:
;Pon el código aquí


main:
mov eax, cadena ;Dirección 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'). Además, únicamente se pueden apilar elementos de 2 o 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 y luego c, las recuperarás en el orden inverso: primero c, luego b y luego a.

Código para invertir cadenas en ensamblador x86

A continuación, el código:
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 Propiedad, 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 débil 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 y terminamos.

Foto: © Bobicova_Valeria - Shutterstock.com

Consulta también :
El documento «Cómo invertir cadenas en ensamblador x86» de CCM (es.ccm.net) se encuentra disponible bajo una licencia Creative Commons. Puedes copiarlo o modificarlo siempre y cuando respetes las condiciones de dicha licencia y des crédito a CCM.