Lenguaje ensamblador - Sintaxis básica
Este capítulo presenta la estructura básica, las reglas de sintaxis y las normas de escritura de los programas en ensamblador NASM, para ayudarte a comprender el esqueleto del código ensamblador.
Estructura básica de un programa ensamblador
Un programa ensamblador NASM completo generalmente consta de las siguientes partes:
Ejemplo
; Ejemplo de estructura básica de un programa NASM
section .data ; Sección de datos: almacena datos inicializados
; Aquí se definen variables y constantes
msg db 'Hello, EJEMPLO!', 0xA
len equ $ - msg
section .bss ; Sección BSS: almacena datos no inicializados
; Aquí se reserva espacio en memoria
buffer resb 64 ; Reservar un búfer de 64 bytes
section .text ; Sección de código: almacena instrucciones ejecutables
global _start
_start:
; Aquí se escribe la lógica del programa
mov eax, 4
mov ebx, 1
mov ecx, msg
mov edx, len
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
| Segmento (Section) | Propósito | Características |
|---|---|---|
.data | Almacena variables globales y constantes inicializadas | El tamaño y el contenido se determinan en tiempo de compilación y se guardan en el archivo ejecutable |
.bss | Almacena variables globales no inicializadas | Solo asigna espacio en tiempo de ejecución y no ocupa espacio en el archivo ejecutable |
.text | Almacena instrucciones de máquina ejecutables | De solo lectura, contiene todo el código lógico del programa |
Se necesitan al menos
.textsegmentos para formar un programa ensamblador válido. Si no hay datos, se pueden omitir.datay.bsslos segmentos.
Formato de las sentencias en ensamblador
El formato general de cada sentencia en ensamblador es:
[标签:] 指令助记符 [操作数1 [, 操作数2 [, 操作数3]]] [; 注释]
Descripción de cada parte:
| Parte | ¿Es obligatorio? | Descripción |
|---|---|---|
| Etiqueta (Label) | Opcional | Un nombre simbólico que representa una dirección de memoria y termina con dos puntos |
| Mnemónico de instrucción | Obligatorio | Como mov, add, sub, etc., le indica a la CPU qué debe hacer |
| Operandos | Opcional (algunas instrucciones no tienen operandos) | El objeto de datos sobre el que opera la instrucción; puede ser un registro, una dirección de memoria o un valor inmediato |
| Comentario | Opcional | Comienza con un punto y coma y se extiende hasta el final de la línea |
Ejemplo
; Solo la instrucción, sin operandos
ret ; Retorno de subrutina
; Instrucción + un solo operando
push eax ; Empuja el valor de eax a la pila
inc ecx ; Incrementa ecx en 1
; Instrucción + dos operandos (el más común)
mov eax, 42 ; Copia 42 al registro eax
add ebx, ecx ; ebx = ebx + ecx
; Con etiqueta
loop_start: ; Etiqueta: marca la posición de inicio del bucle
dec ecx ; Decrementa ecx en 1
jnz loop_start ; Si ecx no es 0, salta de regreso a loop_start
Normas para comentarios
NASM utilizael punto y coma (;)para indicar comentarios; el contenido desde el punto y coma hasta el final de la línea será ignorado por el ensamblador.
Ejemplo
; Calcula la suma de dos números y muestra el resultado
mov eax, 10 ; Comentario en línea: coloca 10 en eax
add eax, 20 ; Comentario en línea: suma 20 a eax, ahora eax = 30
Los comentarios son extremadamente importantes en el código ensamblador. Sin comentarios, el código ensamblador puede resultar incomprensible incluso para su propio autor después de unas semanas. Adquiere el hábito de escribir comentarios en cada instrucción.
Reglas de nomenclatura de identificadores
Los identificadores (etiquetas, nombres de variables, nombres de constantes, etc.) deben seguir las siguientes reglas:
| Regla | Descripción |
|---|---|
| Caracteres permitidos | Letras, dígitos, guion bajo _, punto ., signo de interrogación ?, @, $, #, etc. |
| Carácter inicial | Debe comenzar con una letra, guion bajo, punto o signo de interrogación; no puede comenzar con un dígito |
| Mayúsculas y minúsculas | Distingue entre mayúsculas y minúsculas de forma predeterminada (se puede modificar mediante opciones de compilación) |
| Palabras reservadas | No pueden coincidir con mnemónicos de instrucciones, nombres de registros ni palabras clave de NASM |
Ejemplo
my_variable: ; Comienza con letra + guion bajo
.loop_start: ; Comienza con punto (etiqueta local)
?error_handler: ; Comienza con signo de interrogación
counter2: ; Letra + dígito
; Identificadores no válidos (solo como referencia, no los uses)
; 1st_value: ; Error: no puede comenzar con un dígito
; mov: ; Error: mov es una palabra reservada
; my-variable: ; Error: el guion no es un carácter válido
Directivas
Las directivasson comandos dirigidos al ensamblador, no instrucciones para la CPU; se utilizan para controlar el proceso de ensamblado y definir estructuras de datos.
| Directiva | Propósito | Ejemplo |
|---|---|---|
db | Define un byte (1 byte) | byte_val db 0x55 |
dw | Define una palabra (2 bytes) | word_val dw 0x1234 |
dd | Define una doble palabra (4 bytes) | dword_val dd 0x12345678 |
equ | Define una constante | MAX_SIZE equ 256 |
resb | Reserva espacio en bytes | buffer resb 128 |
resw | Reserva espacio en palabras | wbuf resw 64 |
resd | Reserva espacio en dobles palabras | dbuf resd 32 |
%define | Constante definida con macro | %define COUNT 10 |
Normas de mayúsculas y minúsculas
NASM, por defecto, en cuanto a etiquetas e identificadores,distingue entre mayúsculas y minúsculas.:
Ejemplo
section .data
msg db 'EJEMPLO', 0 ; Define la variable msg
section .text
global _start
_start:
mov eax, MSG ; Error: MSG y msg son diferentes (a menos que se active ignorar mayúsculas y minúsculas)
mov eax, msg ; Correcto: msg coincide exactamente con la definición
MOV EAX, 42 ; Sintaxis correcta: los mnemónicos de instrucciones no distinguen entre mayúsculas y minúsculas
mov eax, 42 ; Escritura recomendada: usar minúsculas para una mejor legibilidad
Los mnemónicos de instrucciones y los nombres de registros no distinguen entre mayúsculas y minúsculas (
MOV、Mov、movel efecto es el mismo), pero el estilo recomendado es usar minúsculas de manera uniforme.
Representación de valores numéricos
NASM admite la representación de valores en múltiples bases:
Ejemplo
mov eax, 42 ; Decimal: escribir el número directamente
mov eax, 0x2A ; Hexadecimal: prefijo 0x (notación recomendada)
mov eax, 2Ah ; Hexadecimal: sufijo h
mov eax, 0o52 ; Octal: prefijo 0o
mov eax, 52o ; Octal: sufijo o
mov eax, 101010b ; Binario: sufijo b
mov eax, 0b101010 ; Binario: prefijo 0b
Se recomienda utilizar
0xel prefijo para representar hexadecimal (como0x2A), de esta manera no es fácil confundirlo con etiquetas.
Un ejemplo completo de sintaxis
El siguiente programa integra los elementos de sintaxis explicados anteriormente, calcula la suma del 1 al 10 y la muestra:
Ejemplo
; Calcula 1+2+...+10 y muestra el carácter del resultado
section .data
result db 0 ; Almacena el resultado del cálculo (1 byte)
newline db 0xA ; Carácter de nueva línea
section .text
global _start
_start:
; Inicializa registros y variables
mov ecx, 10 ; Contador del bucle: comienza la cuenta regresiva desde 10
mov eax, 0 ; eax almacena la suma acumulada, inicialmente 0
sum_loop: ; Etiqueta de inicio del bucle
add eax, ecx ; eax = eax + ecx
dec ecx ; Decrementa ecx en 1
jnz sum_loop ; Si ecx != 0, continúa el bucle
; En este punto eax = 55 (10+9+...+1)
add eax, '0' ; Convierte el número en un carácter ASCII ('0'=48, 55+48=103='g', incorrecto)
; Una demostración real requiere una conversión más compleja; ver capítulos posteriores
; Aquí solo se muestra result (demostración simplificada)
mov [result], al ; Almacena el resultado acumulado en result
; Sale del programa
mov eax, 1
mov ebx, 0
int 0x80
Otras extensionesNota: en el ejemplo anterior, sumar directamente '0' solo es correcto cuando el número está en el rango de 0-9. La conversión de números de dos o más dígitos se explicará en detalle en capítulos posteriores.