Estruturas e Macros STRUC / ENDSTRUC em Assembly NASM
O NASM oferece os macros STRUC e ENDSTRUC para simplificar a definição e o uso de estruturas em Assembly. Com eles, é possível criar modelos reutilizáveis de dados, evitando cálculos manuais de deslocamento (offset) e erros de alinhamento.
Em geral, o trabalho com estruturas no NASM segue três etapas:
- Definir o modelo com
STRUCeENDSTRUC. - Alocar memória (criar instâncias) nas seções
.dataou.bss. - Acessar os campos somando o endereço base com o deslocamento de cada campo.
Definição de um Modelo de Estrutura
A sintaxe básica é a seguinte:
struc nome_estrutura
campo1: tipo1 tamanho1
campo2: tipo2 tamanho2
...
campoN: tipoN tamanhoN
endstruc- O primeiro parâmetro de
STRUCé o nome da estrutura. - O segundo (opcional) define um deslocamento base.
- O bloco entre
STRUCeENDSTRUClista os campos, cada um com nome, tipo e tamanho. - Os tipos são definidos com diretivas de reserva como
resb,resw,resdetc.
Esses macros não alocam memória, apenas definem offsets e o tamanho total da estrutura.
O NASM também cria automaticamente a constante <nome>_size contendo o tamanho total em bytes.
Exemplo:
struc person
.id: resd 1 ; 4 bytes
.name: resb 20 ; 20 bytes
.age: resw 1 ; 2 bytes
endstrucO NASM gerará automaticamente:
| Campo | Offset (bytes) |
|---|---|
| person.id | 0 |
| person.name | 4 |
| person.age | 24 |
| person_size | 26 |
Criação de Instâncias
Após definir o modelo, é possível criar instâncias não inicializadas (em .bss) ou inicializadas (em .data).
Instância Não Inicializada (.bss)
section .bss
person1: resb person_size
person2: resb person_sizeCada instância ocupa 26 bytes.
Instância Inicializada (.data)
Para inicializar campos, usa-se o conjunto de macros ISTRUC, AT e IEND:
section .data
tom:
istruc person
at person.id, dd 101
at person.name, db "Tom", 0
at person.age, dw 2
iendOs campos devem seguir a mesma ordem definida em STRUC.
Acesso aos Campos da Estrutura
O acesso ocorre somando o endereço base ao deslocamento do campo.
Exemplo com a estrutura tom:
mov eax, [tom + person.id] ; EAX = 101
mov bx, [tom + person.age] ; BX = 2
lea esi, [tom + person.name] ; endereço da string "Tom"E exemplo com instância não inicializada:
mov byte [person1 + person.name], 'A'
mov dword [person1 + person.id], 102Exemplo Completo (Linux x86-64)
global _start
; Definição do tipo person
struc person
.id: resd 1
.name: resb 20
.age: resw 1
endstruc
section .data
tom:
istruc person
at person.id, dd 101
at person.name, db "Tom", 10
at person.age, dw 41
iend
section .text
_start:
mov rsi, tom + person.name
mov rdi, 1
mov rdx, person.age - person.name
mov rax, 1
syscall
mov rdi, [tom + person.age]
mov rax, 60
syscallCompilação e Execução
programicio@pc:~$ nasm -f elf64 estrutura.asm -o estrutura.o programicio@pc:~$ ld estrutura.o -o estrutura programicio@pc:~$ ./estrutura Tom programicio@pc:~$ echo $? 41
A execução imprime o nome Tom no terminal e retorna 41, o valor armazenado no campo age.
Resumo
STRUCeENDSTRUCdefinem o modelo da estrutura.ISTRUC,ATeIENDinicializam instâncias em.data.resb,resw,resd,resqdefinem o tamanho de cada campo.- O NASM gera automaticamente
<nome>_sizecom o tamanho total. - Acessos são feitos com
[base + deslocamento].