Saltar a contenido

Assembly File Structure

A medida que aprendemos varias instrucciones de Assembly en las próximas secciones, estaremos constantemente escribiendo código, ensamblándolo y depurándolo. Esta es la mejor manera de aprender lo que hace cada instrucción. Por lo tanto, necesitamos aprender la estructura básica de un archivo de código Assembly y luego ensamblarlo y depurarlo.

En esta sección, revisaremos la estructura básica de un archivo Assembly, y en las dos secciones siguientes, cubriremos cómo ensamblarlo y depurarlo. Trabajaremos con una plantilla de código Assembly llamada Hello World! como ejemplo, para aprender primero la estructura general de un archivo Assembly y luego cómo ensamblarlo y depurarlo. Comencemos analizando una plantilla de código Assembly de ejemplo Hello World!:

         global  _start

         section .data
message: db      "Hello HTB Academy!"

         section .text
_start:
         mov     rax, 1
         mov     rdi, 1
         mov     rsi, message
         mov     rdx, 18
         syscall

         mov     rax, 60
         mov     rdi, 0
         syscall

Este código Assembly (una vez ensamblado y enlazado) debería imprimir la cadena 'Hello HTB Academy!' en la pantalla. No entraremos en detalles sobre cómo se procesa esto todavía, pero necesitamos entender los elementos principales de la plantilla de código.


Assembly File Structure

Primero, examinemos cómo está distribuido el código:

Al observar las partes verticales del código, cada línea puede tener tres elementos:

1. Labels 2. Instructions 3. Operands

Hemos discutido las instructions y sus operands en las secciones anteriores, y entraremos en detalle sobre varias instrucciones de Assembly en las próximas secciones. Además de eso, podemos definir un label en cada línea. Cada label puede ser referido por instructions o por directives.

A continuación, si miramos el código línea por línea, vemos que tiene tres partes principales:

Section Description
global _start Esta es una directive que dirige el código para comenzar a ejecutarse en el label _start definido más abajo.
section .data Esta es la sección de data, que debe contener todas las variables.
section .text Esta es la sección de text que contiene todo el código que se ejecutará.

Tanto las secciones .data como .text se refieren a los segmentos de memoria data y text, en los que se almacenarán estas instrucciones.


Directives

Un código Assembly es basado en líneas, lo que significa que el archivo se procesa línea por línea, ejecutando la instrucción de cada línea. Vemos en la primera línea una directiva global _start, que instruye a la máquina para comenzar a procesar las instrucciones después del label _start. Así, la máquina va al label _start y comienza a ejecutar las instrucciones allí, lo que imprimirá el mensaje en la pantalla. Esto se cubrirá más a fondo en las secciones de Control Instructions.


Variables

A continuación, tenemos la sección .data. La sección de data contiene nuestras variables para facilitar la definición y reutilización de estas sin escribirlas varias veces. Una vez que ejecutamos nuestro programa, todas nuestras variables se cargarán en memoria en el segmento de data.

Cuando ejecutamos el programa, cargará cualquier variable que hayamos definido en memoria para que estén listas para su uso cuando las llamemos. Notaremos más adelante en el módulo que para el momento en que comencemos a ejecutar instrucciones en el label _start, todas nuestras variables ya estarán cargadas en memoria.

Podemos definir variables usando db para una lista de bytes, dw para una lista de palabras, dd para una lista de dígitos, y así sucesivamente. También podemos etiquetar cualquiera de nuestras variables para poder llamarla o referenciarla más tarde. A continuación, algunos ejemplos de definición de variables:

Instruction Description
db 0x0a Define el byte 0x0a, que es una nueva línea.
message db 0x41, 0x42, 0x43, 0x0a Define el label message => abc\n.
message db "Hello World!", 0x0a Define el label message => Hello World!\n.

Además, podemos usar la instrucción equ con el token $ para evaluar una expresión, como la longitud de la cadena de una variable definida. Sin embargo, los labels definidos con la instrucción equ son constantes y no se pueden cambiar más tarde.

Por ejemplo, el siguiente código define una variable y luego define una constante para su longitud:

section .data
    message db "Hello World!", 0x0a
    length  equ $-message

Nota: el token $ indica la distancia actual desde el inicio de la sección actual. Como la variable message está al comienzo de la sección data, la ubicación actual, es decir, el valor de $, equivale a la longitud de la cadena. Para el alcance de este módulo, solo usaremos este token para calcular longitudes de cadenas, usando la misma línea de código mostrada arriba.


Code

La segunda (y más importante) sección es la sección .text. Esta sección contiene todas las instrucciones de Assembly y las carga en el segmento de memoria text. Una vez que todas las instrucciones se cargan en el segmento text, el procesador comienza a ejecutarlas una tras otra.

La convención predeterminada es tener el label _start al comienzo de la sección .text, que -según la directiva global _start- inicia el código principal que se ejecutará a medida que el programa se ejecute. Como veremos más adelante en el módulo, podemos definir otros labels dentro de la sección .text, para bucles y otras funciones.

El segmento text dentro de la memoria es de solo lectura, por lo que no podemos escribir ninguna variable dentro de él. La sección data, por otro lado, es de lectura/escritura, por lo que escribimos nuestras variables en ella. Sin embargo, el segmento data dentro de la memoria no es ejecutable, por lo que cualquier código que escribamos en él no puede ser ejecutado. Esta separación es parte de las protecciones de memoria para mitigar cosas como buffer overflows y otros tipos de explotación binaria.

Tip: Podemos agregar comentarios a nuestro código Assembly con un punto y coma ;. Podemos usar comentarios para explicar el propósito de cada parte del código y qué hace cada línea. Hacer esto nos ahorrará mucho tiempo en el futuro si alguna vez volvemos a revisar el código y necesitamos entenderlo.

Con esto, deberíamos entender la estructura básica de un archivo Assembly.