Hola mundo Ensamblador x86

Josué Acevedo Maldonado
Nabucodonosor Editorial
5 min readApr 24, 2020

No es tan fácil como parece, o tal vez si …

Photo by Victor Aznabaev on Unsplash

Este programa en Ensamblador que se analizara, esta escrito en el ensamblador NASM con sintaxis Intel, para un microprocesador de la familia X86 y se ejecutara en el sistema operativo Gnu/Linux. Todo lo anteriormente dicho, es importante especificar debido a que la forma de escribir el programa y ejecutarlo cambiara en mayor o menor medida si alguno de estos aspectos fuese distinto.

SYS_SALIDA equ 1section .data
msg db "Hola, Mundo!!!",0x0a
len equ $ - msg ;longitud de msg
section .text
global _start ;para el linker
_start: ;marca la entrada
mov eax, 4 ;llamada al sistema (sys_write)
mov ebx, 1 ;descripción de archivo (stdout)
mov ecx, msg ;msg a escribir
mov edx, len ;longitud del mensaje
int 0x80 ;llama al sistema de interrupciones
fin: mov eax, SYS_SALIDA ;llamada al sistema (sys_exit)
int 0x80

Las directivas son comandos que interpreta el programa de ensamblado, este programa se encuentra constituido por las directivas que se mencionan a continuación.

Segmentos de memoria

En el lenguaje ensamblador es necesario especificar que instrucciones se guardaran en la memoria correspondiente a los datos y que otros se almacenaran en la memoria de código, para esto se utilizan los segmentos. En NASM los segmentos se especifican mediante la directiva section, de esta forma:

  • section .data
    Define el grupo de declaraciones inicializadas, ubicadas en el segmento de datos de la memoria principal.
  • section .text
    Define el grupo de instrucciones a ser ejecutadas, ubicadas en el segmento de código de la memoria principal.
  • section .bss
    Define el grupo de declaraciones no inicializadas, ubicadas de forma adyacente al segmento de datos de la memoria principal. bss es una abreviatura de ’block started by simbol

Etiquetas

Su función es facilitar al programador la tarea de hacer referencia a una dirección de memoria, ya sea del segmento de datos o de código, mediante un símbolo o nombre. De esta manera se tienen dos tipos de etiquetas:

Para hacer referencia a una posición de código dentro del programa.

SYS_SALIDA equ 1section .data
msg db "Hola, Mundo!!!",0x0a
len equ $ - msg ;longitud de msg
section .text
global _start ;para el linker
_start: ;marca la entrada
mov eax, 4 ;llamada al sistema (sys_write)
mov ebx, 1 ;descripción de archivo (stdout)
mov ecx, msg ;msg a escribir
mov edx, len ;longitud del mensaje
int 0x80 ;llama al sistema de interrupciones
fin: mov eax, SYS_SALIDA ;llamada al sistema (sys_exit)
int 0x80

Para hacer referencia a las variables y constantes del programa.

SYS_SALIDA equ 1section .data
msg db "Hola, Mundo!!!",0x0a
len
equ $ - msg ;longitud de msg
section .text
global _start ;para el linker
_start: ;marca la entrada
mov eax, 4 ;llamada al sistema (sys_write)
mov ebx, 1 ;descripción de archivo (stdout)
mov ecx, msg ;msg a escribir
mov edx, len ;longitud del mensaje
int 0x80 ;llama al sistema de interrupciones
fin: mov eax, SYS_SALIDA ;llamada al sistema (sys_exit)
int 0x80

La etiqueta _start: dentro del segmento de código es una etiqueta especial y sirve para indicarle al ensamblador donde es que comienza el programa, por lo que es necesaria la directiva global _start para que esta etiqueta presente un alcance externo; es similar a la función que cumple el main en los lenguajes de alto nivel.

Definición de datos

Las directivas usadas para especificar los datos del programa, se declaran mediante:

· Un nombre, el cual sigue las mismas reglas que la etiqueta de una posición de código con la excepción del uso del carácter dos puntos (:).

· Una instrucción de asignación de espacio en memoria, por ejemplo: DB (Define Byte): Se utiliza para asignar un byte (8 bits) de almacenamiento a cada uno de los datos declarados con esta directiva. En la mayoría de los lenguajes de programación de alto nivel, esta misma cantidad de memoria es utilizada para almacenar los tipos de datos char, debido a que los caracteres en su representación decimal solo llegan hasta el 255

· y el valor o valores a almacenar en la memoria separados por comas.

SYS_SALIDA equ 1section .data
msg db "Hola, Mundo!!!",0x0a
len equ $ - msg ;longitud de msg
section .text
global _start ;para el linker
_start: ;marca la entrada
mov eax, 4 ;llamada al sistema (sys_write)
mov ebx, 1 ;descripción de archivo (stdout)
mov ecx, msg ;msg a escribir
mov edx, len ;longitud del mensaje
int 0x80 ;llama al sistema de interrupciones
fin: mov eax, SYS_SALIDA ;llamada al sistema (sys_exit)
int 0x80

En combinación a la declaración de constantes, NASM permite realizar un par de pseudo operaciones para el cálculo de direcciones de memoria mediante dos constantes especiales $ y $$.

$ : Hace referencia a la dirección de memoria actual.

 letrero db “texto”
tamanio EQU $- letrero
;al restar la dirección de memoria ubicada al final
;del mensaje “texto” ($) y la dirección de memoria donde este
;mismo comienza mediante su nombre ‘letrero’, la variable
;tamanio almacena la longitud del contenido de la variable
;’letrero’ en bytes (5 bytes)

Interrupciones

En ensamblador para realizar cualquier acción con el hardware , ya sea imprimir en pantalla o leer datos desde el teclado se necesita la intervención del sistema operativo ,al menos en los sistemas modernos asi ocurre, para lograr esto es necesario invocar la acción del sistema con un valor de interrupción el cual variara dependiendo del sistema operativo donde el programa se ejecutara, además de esto los datos que se le pasaran serán distintos, por lo que este ejemplo funciona en el sistema operativo Gnu/Linux, pero no en cualquier otro como por ejemplo Windows.

SYS_SALIDA equ 1section .data
msg db "Hola, Mundo!!!",0x0a
len equ $ - msg ;longitud de msg
section .text
global _start ;para el linker
_start: ;marca la entrada
mov eax, 4 ;llamada al sistema (sys_write)
mov ebx, 1 ;descripción de archivo (stdout)
mov ecx, msg ;msg a escribir
mov edx, len ;longitud del mensaje
int 0x80 ;llama al sistema de interrupciones
fin: mov eax, SYS_SALIDA ;llamada al sistema (sys_exit)
int 0x80

Para finalizar ensamblaremos, ligaremos y ejecutaremos el programa.

nasm -f elf hola_mundo.asm 
#crea el archivo hola_mundo.o
ld -m -o elf_i386 hola_mundo hola_mundo.o
#crea el archivo ejecutable hola_mundo
./hola_mundo
#ejecuta nuestro programa

Josue Acevedo Maldonado es ingeniero de software, trabaja actualmente como consultor.

Conectarse en LinkedIn.

¡Gracias por ser parte de la comunidad!
Puede encontrar contenido relacionado en el canal de YouTube, Twitter, Twitch, Spotify, etc, ademas del libro Ensamblador X86.

Si ha disfrutado de este artículo y siente que ha aprendido algo valioso, por favor compártalo.

¡Gracias por leer!

--

--

Josué Acevedo Maldonado
Nabucodonosor Editorial

Amante de la tecnologia y con pasion en resolver problemas interesantes, consultor, y creador del canal de youtube NEOMATRIX. https://linktr.ee/neomatrix