← Voltar aos artigos

Convenções de assembly da trilha

Uma sintaxe, um montador

Assembly ARM tem duas famílias de sintaxe. A antiga (divided, pré-2005) escrevia as instruções Thumb e ARM de formas diferentes. A atual é a UAL — Unified Assembler Language: o mesmo mnemônico serve para ARM e Thumb, e o montador escolhe a codificação pelo modo (.arm / .thumb). Toda a trilha usa UAL, ligada explicitamente com:

    .syntax unified

O montador é o arm-none-eabi-as do toolchain GNU (arm-none-eabi, instalado no artigo de ambiente). É o mesmo as do GCC — então a sintaxe de diretivas é a do GAS (GNU assembler), não a do armasm da ARM. As diferenças que importam:

ItemGAS (esta trilha)armasm (ARM)
Comentário de linha@ comentário; comentário
Comentário de bloco/* ... */—
Rótulonome:nome (coluna 1)
Constante.word 0x10DCD 0x10
Seção de código.text`AREA

Diretivas do GAS que vão aparecer

Um .s típico da trilha tem esta cara (armbox/testdata/hello.s):

    .arch armv5te        @ arquitetura alvo (afeta quais instruções são aceitas)
    .arm                 @ montar em estado ARM (32 bits). Alternativa: .thumb
    .text                @ o que vem abaixo vai para a seção de código
    .global _start       @ exporta o símbolo _start (o linker precisa dele)
_start:                  @ um rótulo = um endereço
    mov     r0, #1
    svc     #0
msg:
    .ascii  "hello from a real ELF\n"   @ bytes crus na seção atual
msg_end:
DiretivaO que faz
.arch <nome>Define a arquitetura alvo (armv4t, armv5te, armv6k, armv7-a, ...). Instrução fora do alvo → erro de montagem
.arm / .thumbSeleciona o estado; muda a largura e a codificação das instruções
.syntax unifiedLiga a UAL (recomendado sempre)
.text / .data / .bssSeção de código / dados inicializados / dados zerados
.global <sym>Torna o símbolo visível para o linker
.word / .hword / .byteEmite 4 / 2 / 1 bytes literais
.ascii / .ascizString sem / com terminador NUL
.align n / .balign nAlinha o próximo dado a 2^n / n bytes
.equ NOME, valorConstante de montagem (sem custo em runtime)

Anatomia de um mnemônico

O formato geral de uma instrução de processamento de dados é:

<mnemônico>{<cond>}{S}  Rd, Rn, <Operand2>
  • {cond} — sufixo de condição (EQ, NE, GE, LT, ...). Quase toda instrução ARM pode ser condicional; sem sufixo, é AL (always).
  • {S} — se presente, a instrução atualiza as flags N/Z/C/V do CPSR. ADD não mexe nas flags; ADDS mexe.
  • Operand2 — um imediato (#42), um registrador (r3) ou um registrador deslocado (r3, LSL #2).

Imediatos levam #: mov r0, #1. Registradores são r0–r15 (com apelidos sp = r13, lr = r14, pc = r15).

Como os listings são apresentados

Ao longo da trilha, código aparece de três formas:

1. O fonte comentado — o .s que você escreve, com @ explicando a intenção.

2. A desmontagem do objdump -d — o que a máquina realmente executa:

00008000<_start>:
8000:e3b00005movsr0, #5
8004:e3a01a01movr1, #4096@ 0x1000
00008008<loop>:
8008:e2500001subsr0, r0, #1
800c:1afffffdbne8008 <loop>
8010:12811004addner1, r1, #4
8014:e12fff1ebxlr

Cada linha é endereço:   bytes da codificação   mnemônico desmontado. A coluna do meio (e3b00005, e2500001, ...) é a instrução de 32 bits em hexadecimal, little-endian no arquivo mas mostrada aqui já na ordem lógica. Decodificar essa coluna à mão é o módulo 2.

3. Sessões de depuração — trechos de gdb mostrando registradores e flags mudando instrução a instrução (padrão do artigo de GDB).

O que esse exemplo já ensina

Dois detalhes do listing acima:

  • ldr r1, =0x1000 sumiu. No fonte estava a pseudo-instrução ldr r1, =0x1000; o montador viu que 0x1000 cabe num imediato codificável e trocou por mov r1, #4096. Pseudo-instruções (ldr Rd, =const, adr, nop) são conveniências do montador — não existem no binário.
  • addne r1, r1, #4 tem cond = NE. A codificação 12811004 começa com o nibble 1 (condição NE); a versão incondicional (add) começaria com e (AL). É a predicação em ação: a instrução ocupa espaço e tempo, mas só tem efeito se Z == 0. O artigo de flags explora isso.

Comandos do toolchain

ComandoO que faz
arm-none-eabi-as -march=armv5te -o x.o x.sMonta x.s → objeto x.o
arm-none-eabi-ld -Ttext=0x10000 -o x.elf x.oLiga x.o → executável x.elf, código em 0x10000
arm-none-eabi-gcc -nostdlib -o x.elf x.sMonta e liga em um passo (sem libc)
arm-none-eabi-objdump -d x.elfDesmonta a seção de código
arm-none-eabi-objdump -s -j .data x.elfDump hexadecimal de uma seção
arm-none-eabi-objcopy -O binary x.elf x.binExtrai só os bytes (sem cabeçalho ELF)

Próximo passo

Com a notação combinada, o módulo 1 entra nos fundamentos: o banco de registradores, o CPSR e a diferença entre ARM e Thumb.

Trilha: Curso de Arquitetura ARM · Módulo 0, lição 3.