A extensão padrão é .s(o ideal é para identificação), mas você pode usar qualquer extensão desde que haja somente código GAS dentro do arquivo, exemplos: .gas, .as e .S.
Conceito inicial sobre Registradores
Os registradores em assembly x86_64 são utilizados para armazenar dados temporários e realizar operações aritméticas e lógicas. São eles:
Registradores de Propósito Geral (64 bits)
RAX (Accumulator Register): Usado para operações aritméticas e retornos de funções.
RBX (Base Register): Pode ser usado para acessar dados na memória.
RCX (Counter Register): Utilizado como contador em loops e operações de repetição.
RDX (Data Register): Usado em operações aritméticas e I/O.
RSI (Source Index): Utilizado como ponteiro de origem em operações de string.
RDI (Destination Index): Utilizado como ponteiro de destino em operações de string.
RBP (Base Pointer): Utilizado para apontar para a base de uma stack frame.
RSP (Stack Pointer): Aponta para o topo da pilha.
R8-R15: Registradores adicionais de propósito geral.
Registradores Segment (16 bits)
CS (Code Segment): Segmento de código.
DS (Data Segment): Segmento de dados.
SS (Stack Segment): Segmento de pilha.
ES, FS, GS: Segmentos adicionais utilizados em operações de dados específicos.
Registradores de Propósito Especial
RIP (Instruction Pointer): Aponta para a próxima instrução a ser executada.
RFLAGS (Flags Register): Contém flags de status e controle, como carry, zero, sign, overflow, etc.
Registradores de Propósito Geral (32 bits)
EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP: Versões de 32 bits dos registradores de 64 bits.
R8D-R15D: Versões de 32 bits dos registradores R8-R15.
Registradores de Propósito Geral (16 bits)
AX, BX, CX, DX, SI, DI, BP, SP: Versões de 16 bits dos registradores de 64 bits.
R8W-R15W: Versões de 16 bits dos registradores R8-R15.
Registradores de Propósito Geral (8 bits)
AH, AL, BH, BL, CH, CL, DH, DL: Subdivisões dos registradores de 16 bits (AX, BX, CX, DX).
R8B-R15B: Versões de 8 bits dos registradores R8-R15.
SPL, BPL, SIL, DIL: Versões de 8 bits dos registradores SP, BP, SI, DI.
Registradores de Vetor/SIMD
XMM0-XMM15: Usados para operações SIMD (Single Instruction, Multiple Data) de 128 bits.
YMM0-YMM15: Versões de 256 bits dos registradores XMM.
ZMM0-ZMM31: Versões de 512 bits dos registradores XMM, usados em AVX-512.
Exemplos de Uso:
RAX: Guardar resultado de uma operação de multiplicação.
RSI e RDI: Usados em operações de copiar memória (movsb, movsw, movsd, movsq).
RCX: Usado como contador de loop (loop).
Esses são os principais registradores em GAS/NASM para x86_64. Eles são essenciais para manipulação de dados, controle de fluxo, e execução de operações em programas assembly.
Diferença entre os registradores GAS e NASM
Os registradores possuem o mesmo conceito e funcionalidade básica tanto no NASM quanto no GNU Assembler (GAS) para a arquitetura x86_64. A principal diferença entre NASM e GAS é a sintaxe usada para escrever os programas, mas os registradores e suas utilizações permanecem consistentes.
Agora veremos alguns exemplos de códigos básicos para nos adaptarmos como a sintaxe é utilizada.
01. Criando um “Hello, World!”
.section .data: Declara a seção de dados, onde as variáveis e strings são armazenadas.
hello: .ascii "Hello, World!\0": Define uma string terminada em nulo (0).
.section .text: Declara a seção de código, onde o código executável é armazenado.
.globl _start: Torna a label _start visível para o linker.
_start: Ponto de entrada do programa.
mov $1, %rax: Coloca o número do syscall sys_write no registrador rax.
mov $1, %rdi: Coloca o número do file descriptor (stdout) no registrador rdi.
mov $hello, %rsi: Coloca o endereço da stringhello no registrador rsi.
mov $13, %rdx: Coloca o comprimento da string no registrador rdx.
syscall: Chama o kernel para executar o syscall.
mov $60, %rax: Coloca o número do syscall sys_exit no registrador rax.
xor %rdi, %rdi: Zera o registrador rdi para definir o status de saída como 0.
syscall: Chama o kernel para terminar o programa.
Compilar e executar:
No Windows é o hello.exe em vez de ./hello.
Após rodar, note que o Hello, World! vai colar com o prompt:
Para resolver isso, troque o \0 por \n:
E aumente o comprimento da string para 14 bytes (13 caracteres + 1 para a quebra de linha \n):
Recompile e rode!
Comparação do GAS com NASM
Mesmo código, mas com NASM:
Para compilar e rodar o NASM:
Note: Além do símbolo %(do GAS) na frente do registradores e os comentários serem #(GAS) e ;(NASM), o GAS também pode comentar estilo C: /* Comentário para multiplas linhas */, além de outras formas dependendo da arquitetura, exemplos:
Embora a sintaxe seja diferente (NASM usa uma abordagem mais “intel” enquanto GAS usa uma abordagem “AT&T”), os registradores desempenham as mesmas funções em ambas as assemblers.
Há outros Assemblers
Além do GNU Assembler (GAS) e do NASM (Netwide Assembler), existem vários outros assemblers conhecidos e amplamente utilizados. Aqui estão alguns dos mais notáveis:
MASM (Microsoft Macro Assembler):
Utilizado principalmente para desenvolvimento em plataformas Windows.
Suporta diversas versões de sintaxe e é frequentemente usado para desenvolver drivers e outros componentes de baixo nível.
FASM (Flat Assembler):
Um assembler de código aberto e multiplataforma.
Conhecido por sua velocidade e capacidade de compilar a si mesmo.
TASM (Turbo Assembler):
Desenvolvido pela Borland.
Era popular nos anos 80 e 90 e frequentemente utilizado em conjunto com o Turbo C e outras ferramentas Borland.
YASM:
Um assembler de baixo nível compatível com a sintaxe NASM.
Suporta x86 e x86-64 e é projetado para ser rápido e extensível.
A86/A386:
Um assembler DOS shareware para programação x86.
Conhecido por ser fácil de usar e eficiente.
HLA (High-Level Assembler):
Desenvolvido por Randall Hyde, conhecido por seu livro “The Art of Assembly Language”.
Proporciona uma sintaxe de alto nível que facilita o aprendizado e o uso do assembly.
SPIM:
Um assembler e simulador para a arquitetura MIPS.
Frequentemente utilizado em cursos universitários para ensino de assembly MIPS.
Keil Assembler:
Parte do conjunto de ferramentas Keil para microcontroladores, especialmente populares para desenvolvimento com ARM.
TASM (Turbo Assembler):
Desenvolvido pela Borland, é um assembler antigo que foi muito usado nos anos 80 e 90.
Esses assemblers são usados em diferentes contextos, desde desenvolvimento de sistemas embarcados até programação de aplicações de baixo nível em diversas plataformas. Cada um tem suas próprias características e sintaxes que podem ser mais adequadas para determinadas tarefas e ambientes de desenvolvimento.
02. Criando “Hello, World!” com Variável
.lcomm buffer, 13: Reserva 13 bytes para o buffer na seção BSS.
call copy_string: Chama a função copy_string para copiar a stringhello para o buffer.
copy_string: Função que copia a string para o buffer.
mov $13, %rcx: Define o contador de repetição para o comprimento da string.
loop .loop: Laço de repetição para copiar cada byte da string.
03. Criando um Função que imprime: “Hello, World!”
call print_hello: Chama a função print_hello para imprimir a stringhello;
print_hello: Função que executa o syscall sys_write para imprimir a string.
04. Escrevendo um código que: Soma de Dois Números
E imprime na tela com quebra de linha/nova linha (sem colar no prompt)!
num1: .quad 5 e num2: .quad 10: Define os números a serem somados.
result: .quad 0: Reserva espaço para armazenar o resultado.
add num2(%rip), %rax: Soma num2 ao valor de num1 armazenado em rax.
mov %rax, result(%rip): Armazena o resultado da soma.
call print_result: Chama a função print_result para imprimir o resultado.
Após cadastro e confirmação do e-mail, enviaremos semanalmente resumos e também sempre que houver novidades por aqui para que você mantenha-se atualizado!