Aprende ASM

En estos momentos empezamos a publicar información con apoyo de los del grupo de facebook para todos aquellos que deseen aprender programación en Ensamblador.

 

Este post es patrocinado por: David Moreno 

Hello World para x86 en Linux

David Moreno

(Ascii Art destrozada por Facebook)

—-

El tradicional Hello World en ensamblador para Linux

—————————————————————-

Para ensamblarlo utilizaremos dos programas: nasm y ld. Ambos son programas GNU y están disponibles en la mayoría de sistemas de paquetes.

Los que utilizen una distro derivada de Debian (Ubuntu) pueden instalarnasm fácilmente:

    sudo apt-get install nasm

ld, es casi seguro que ya esté instalado, pero si no fuese así, pueden instalar el paquete binutils, el cual contiene (entre otros programas muy útiles) a ld:

    sudo apt-get install binutils
¿Qué son nasm y ld?

————————-

nasm es un ensamblador. Sirve para convertir el código fuente a código objeto.
ld es un linker (enlazador). Toma código objeto y lo convierte en unejecutable.

+—————+
|                    |
+———–+     | Ensamblador |    +——–+
|               |     |                   |     |           |
| hello.asm |–>|     (nasm)     |–>| hello.o |
|               |     |                   |     |           |
+———–+     +————–+     +——–+

+———–+
|               |
+——–+    | Enlazador |    +——+
|           |     |              |     |        |
| hello.o |–>|     (ld)     |–>| hello |
|           |     |              |     |        |
+——–+    +———–+    +——+

¿¿Código objeto??

———————-

El proceso de ensamblado en realidad es una traducción, como cuando se traduce un documento del inglés al español. Si nosotros no hablamos inglés no podremos comprender el documento, pero una vez traducido ya lo entenderemos.

De esta forma se traduce el programa fuente (hello.asm), escrito en palabras fáciles de recordar para una persona como mov, push o int a instrucciones binarias que son entendibles para la máquina, pero no para un ser humano (a menos que seas un geek o un hacker de los 70’s). El resultado es hello.o (el código objeto).

En esta tabla se muestran las instrucciones en lenguaje ensamblador y su equivalente en código de máquina expresado en hexadecimal (el prefijo 0x indica que es un valor hexadecimal):

+————————-+—————–+
| ASM                         | HEX               |
+————————-+—————–+
| mov   eax,0x4           | b8 04 00 00 00 |
| mov   ebx,0x1           | bb 01 00 00 00 |
| mov   ecx,0x80490a0  | b9 a0 90 04 08 |
| mov   edx,0x26          | ba 26 00 00 00 |
| int   0x80                  | cd 80              |
| mov   eax,0x1            | b8 01 00 00 00 |
| xor   ebx,ebx             | 31 db              |
| int   0x80                  | cd 80              |
+————————-+——————+

Algunas instrucciones son fáciles de reconocer, como int que en hexadecimal equivale a 0xcd (205 en decimal), otras no son tan intuitivas.

El enlazador toma este código objeto y lo prepara para producir un programa ejecutable.

Ensamblando el programa

——————————

Primero, ensamblamos el programa, indicando a nasm que produzca código objeto del tipo ELF (el utilizado por los ejecutables en Linux):

    nasm -f elf hello.asm

nasm creará un nuevo archivo (hello.o), el cual enlazamos con ld, indicándole el nombre del ejecutable (Linux no necesita la extención exeen los ejecutables):

    ld -o hello hello.o

Listo, ahora ya podemos escribir en la terminal el nombre del programa para ejecutarlo:

    ./hello

Y aquí el código de hello.asm (las líneas que comienzan en ‘;‘ son comentarios):

; ======== PRINCIPIO DE HELLO.ASM ========
section .data
msg db “Hola mundo”, 0x0a ;Mensaje
len equ $ – msg         ;Tamaño del mensaje

section .text
global _start         ;Necesitamos exportar ‘_start’ a ld, para que lo reconozca
;como el punto de entrada del programa.

_start:
;Escribimos el saludo a stdout.
mov eax, 4           ;Número de la llamada al sistema (sys_write).
mov ebx, 1           ;Primer argumento: file handle (stdout).
mov ecx, msg         ;Segundo argumento: puntero a la cadena a escribir.
mov edx, len         ;Tercer argumento: tamaño de la cadena.
int 0x80             ;Llama al Kernel.

mov eax, 1           ;Número de la llamada al sistema (sys_exit).
xor ebx, ebx         ;Argumento de la llamada: código de salida (0: ejecución exitosa).
int 0x80             ;Llama al Kernel.
; ======== FIN DE HELLO.ASM ========