Definição de Variáveis e Tipos de Dados em Assembly NASM: Seção .data
Tipos de Dados
Todos os dados utilizados em um programa Assembly possuem um tipo, determinado pela sua largura em bits. A arquitetura Intel x86-64 oferece os seguintes tipos básicos:
- byte – número inteiro de 8 bits
- word – número inteiro de 16 bits (palavra)
- dword – número inteiro de 32 bits (palavra dupla)
- qword – número inteiro de 64 bits (palavra quádrupla)
Por exemplo, o registrador de 8 bits AL representa um byte, AX representa uma palavra de 16 bits, EAX uma palavra dupla de 32 bits e RAX uma palavra quádrupla de 64 bits.
Definição de Dados no Programa
O NASM permite definir objetos que armazenam dados diretamente no código fonte. Esses objetos podem ser utilizados e modificados durante a execução do programa — em outras palavras, são variáveis.
A forma geral de definição é:
label directive value
O identificador label é o nome da variável.
Em seguida vem a diretiva que indica o tipo de dado, e por fim o valor inicial.
As diretivas mais comuns são:
db– define um número inteiro de 1 bytedw– define um número inteiro de 2 bytesdd– define um número inteiro de 4 bytesdq– define um número inteiro de 8 bytes
Exemplo
number dq 22
A variável number é um valor de 8 bytes (qword) inicializado com 22.
Também é possível adicionar dois-pontos após o nome, mas isso é opcional:
number: dq 22
O assembler reserva um espaço de 8 bytes na memória e o associa à variável number.
Localização e Uso dos Dados
Os dados podem ser definidos em diferentes seções do programa Assembly.
Definindo Dados na Seção .text
Também é possível declarar dados dentro da seção de código .text:
global _start
section .text
number: dq 123 ; definição de dado dentro da seção .text
_start:
; restante do códigoÉ importante não misturar instruções com declarações de dados. As variáveis devem aparecer antes da primeira instrução ou após a última.
O nome da variável representa seu endereço na memória, e não o valor armazenado. Por exemplo:
global _start
section .text
number: dq 124
_start:
mov rdi, number ; move o endereço da variável para RDI
mov rax, 60
syscallPara acessar o valor contido na variável, usa-se colchetes:
mov rdi, [number]Assim, o registrador RDI receberá o valor 124:
global _start
section .text
number: dq 124
_start:
mov rdi, [number] ; RDI = 124
mov rax, 60
syscallParticularidades no Windows
Em Windows, o uso de variáveis na seção .text pode gerar erros de relocação durante a vinculação.
global _start
section .text
number: db 124
_start:
mov rax, [number]
retAo compilar com o ld (GCC), ocorre:
relocation truncated to fit: IMAGE_REL_AMD64_ADDR32 against `.text`
E com o link.exe (Microsoft):
error LNK2017: 'ADDR32' relocation to '.text' invalid without /LARGEADDRESSAWARE:NO
O problema surge porque o programa de 64 bits tenta usar endereços de 32 bits.
Embora seja possível contornar com /LARGEADDRESSAWARE:NO, a solução correta é usar o operador rel, que acessa o endereço relativo ao registrador RIP (Instruction Pointer):
mov rax, [rel number]Versão corrigida:
global _start
section .text
number: dq 124
_start:
mov rax, [rel number]
retEssa abordagem funciona com o link.exe, mas pode produzir resultados incorretos ao usar o ld do GCC.
Em resumo, a seção .text não é adequada para armazenar dados.
Seção .data
A seção .data é o local apropriado para armazenar dados modificáveis.
Ela é declarada com:
section .data
Exemplo no Linux
global _start
section .data
number dq 125
section .text
_start:
mov rdi, [number]
mov rax, 60
syscallExemplo no Windows
global _start
section .data
number dq 125
section .text
_start:
mov rax, [rel number]
retA seção .data é ideal para variáveis, e ambos os vinculadores (ld e link.exe) tratam-na corretamente.
Organização dos Dados em Memória
Quando várias variáveis são declaradas na seção .data, o NASM aloca blocos de memória consecutivos para cada uma:
section .data
i64 dq 8
i32 dd 4
i16 dw 2
i8 db 1A variável i64 ocupa 8 bytes, i32 ocupa 4 bytes, i16 ocupa 2 e i8 ocupa 1.
Essas variáveis são armazenadas em sequência na memória.

Se i64 começa no endereço 0x0000, então:
i32estará em 0x0008i16em 0x000Ci8em 0x000E
Alteração de Dados
Variáveis definidas na seção .text se comportam como constantes, pois essa seção é marcada como somente leitura.
global _start
section .text
number dq 124
_start:
mov rdx, 111
mov [number], rdx ; tentativa de sobrescrita
mov rdi, [number]
mov rax, 60
syscallAo executar, o sistema gera segmentation fault, pois .text não permite escrita.
A solução é mover os dados para .data:
global _start
section .data
number dq 125
section .text
_start:
mov rdx, 111
mov [number], rdx
mov rdi, [number]
mov rax, 60
syscallAgora o valor pode ser alterado normalmente.
Exemplo equivalente no Windows
global _start
section .data
number dq 125
section .text
_start:
mov rdx, 111
mov [rel number], rdx
mov rax, [rel number]
retDefinição de Conjuntos e Arrays
O NASM permite definir conjuntos de dados (arrays). Se os valores iniciais forem conhecidos, basta listá-los:
nums dq 11, 12, 13, 14, 15, 16, 17A variável nums representa um conjunto de 7 números de 8 bytes cada.
O nome da variável corresponde ao primeiro elemento do conjunto.
global _start
section .data
nums dq 11, 12, 13, 14, 15, 16, 17
section .text
_start:
mov rdi, [nums] ; RDI = 11
mov rax, 60
syscallTambém é possível repetir valores usando a diretiva times:
label: times N type value
Exemplo:
numbers: times 10 db 2
Cria um array de 10 bytes, todos com o valor 2.
Para reservar espaço sem inicializar valores, o NASM oferece as diretivas resX:
resb– reserva bytesresw– reserva palavras (2 bytes)resd– reserva palavras duplas (4 bytes)resq– reserva palavras quádruplas (8 bytes)
Cada posição é automaticamente preenchida com zeros.
buffer resb 10
numbers resq 5Outras Seções de Dados
Além da .data, o NASM oferece outras seções específicas:
Seção .rodata
Armazena dados somente leitura, ou seja, constantes.
global _start
section .rodata
number dq 125
section .text
_start:
mov rdi, [number]
; mov [number], rdi - causaria Segmentation fault
mov rax, 60
syscallQualquer tentativa de escrita nessa área provoca erro de proteção.
Seção .bss
A seção .bss (Block Started by Symbol) contém dados não inicializados.
Somente o tamanho é definido; os valores são preenchidos com zeros na execução.
Isso reduz o tamanho do arquivo binário.
global _start
section .bss
buffer resq 1024 ; 1024 números de 8 bytes
section .text
_start:
mov rdi, [buffer] ; RDI = 0
mov rax, 60
syscallO array ocupa 1024 × 8 = 8192 bytes na memória, mas não aumenta o tamanho do executável.
Conversão e Tamanho dos Dados
Ao manipular dados, é essencial respeitar a largura dos registradores e variáveis. Por exemplo:
global _start
section .data
number db 12
section .text
_start:
mov rdi, [number]
mov rax, 60
syscallAqui, um valor de 8 bits é movido para um registrador de 64 bits. O sistema preenche automaticamente os bytes superiores com zeros, e a execução ocorre sem erros.
Versão para Windows:
global _start
section .data
number db 12
section .text
_start:
mov rax, [rel number]
retAmbas exibem corretamente o valor 12.
Conversão Explícita e Carregamento de Arrays
global _start
section .data
nums db 1, 2, 0, 0, 0, 0, 0, 0
section .text
_start:
mov rax, [rel nums]
retO array nums contém 8 bytes.
Como o registrador RAX também tem 8 bytes, todos os elementos são carregados de uma vez, gerando o valor 513.
Isso ocorre porque os dois primeiros bytes (1 e 2) formam o número binário:
00000010_00000001b - 513
Para carregar apenas o primeiro byte, é necessário indicar o tamanho e expandir corretamente:
movzx rax, byte [rel nums]
O operador byte limita a leitura, e movzx preenche os demais bytes do registrador com zeros.
Da mesma forma, ao gravar valores, deve-se indicar o tamanho:
mov byte [nums], 101Exemplo completo no Linux
global _start
section .data
nums db 12, 13, 14, 15
section .text
_start:
mov byte [nums], 101 ; altera o primeiro elemento
movzx rdi, byte [nums] ; RDI = 101
mov rax, 60
syscallResumo
.text: código executável (constante, não modificável).data: variáveis inicializadas.bss: variáveis não inicializadas.rodata: dados somente leituradb,dw,dd,dq: tamanhos de 1, 2, 4 e 8 bytesresX: reserva espaço sem inicializarrel: acesso relativo ao registrador RIP (Windows 64-bit)movzx+byte/word/dword/qword: conversão e carregamento com tamanho definido