Aprendendo Assembly
Doar para o autor
  • Introdução
  • Conteúdo
  • Como usar este livro
  • A base
    • Noção geral da arquitetura
    • Modos de operação
    • Sintaxe
    • Registradores de propósito geral
    • Endereçamento
    • Pilha
    • Saltos
    • Procedimentos
    • Seções e símbolos
    • Instruções assembly x86
    • Instruções do NASM
    • Pré-processador do NASM
    • Syscall no Linux
    • Olá mundo no Linux
    • Revisão
  • Aprofundando em Assembly
    • Registradores de segmento
    • CALL e RET
    • Position-independent executable
    • Atributos
    • Prefixos
    • Flags do processador
    • Instruções condicionais
    • Programando no MS-DOS
    • Interrupções de software e exceções
    • Procedimentos do BIOS
    • Usando instruções da FPU
    • Entendendo SSE
      • Instruções de movimentação de dados
      • Instruções aritméticas
      • Instruções lógicas e de comparação
      • Instruções com inteiros 128-bit
      • Instruções de conversão
  • Programando junto com C
    • Sintaxe do GAS
    • Convenção de chamada da System V ABI
    • Convenções de chamada no Windows
    • Variáveis em C
    • Funções em C
    • Ambiente hosted
    • Ambiente freestanding
    • Inline Assembly no GCC
    • Instruções intrínsecas
  • Depuração de código
    • Entendendo os depuradores
    • Depurando com o GDB
    • Depurando com o Dosbox
  • Apêndices
    • Código de máquina
      • Formato das instruções
      • Atributos e prefixos
      • Immediate
      • Displacement
      • ModR/M e SIB
      • Opcode
      • Prefixo REX
      • Codificação dos registradores
  • Metadados
    • TO DO
    • Referências
Powered by GitBook
On this page
  • Diferenças entre sintaxe Intel e AT&T
  • Tamanho dos operandos
  • Far jump e call
  • Endereçamento
  • Saltos
  • Aprendendo a usar o GAS
  • Comentários
  • Pseudo-instruções de dados
  • Diretivas de seções e alinhamento
  • Usando sintaxe Intel
  • Exemplo de código na sintaxe AT&T

Was this helpful?

Export as PDF
  1. Programando junto com C

Sintaxe do GAS

Aprendendo a sintaxe AT&T e a usar o GAS

O GNU assembler (GAS) usa por padrão a sintaxe AT&T e neste tópico irei ensiná-la. Mais abaixo irei ensinar a diretiva usada para usar sintaxe Intel meramente como curiosidade e caso prefira usá-la.

Diferenças entre sintaxe Intel e AT&T

A primeira diferença notável é que o operando destino nas instruções de sintaxe Intel é o mais à esquerda, o primeiro operando. Já na sintaxe da AT&T é o inverso, o operando mais à direita é o operando destino. Conforme exemplo:

# Isso é um comentário.

# Sintaxe AT&T       # Sintaxe Intel

mov $123, %eax       # mov eax, 123
mov $0x0A, %eax      # mov eax, 0x0A
mov $0b1010, %eax    # mov eax, 0b1010
mov $'A', %eax       # mov eax, 'A'

E como já pode ser observado valores literais precisam de um prefixo $, enquanto os nomes dos registradores precisam do prefixo %.

Tamanho dos operandos

Na sintaxe da Intel o tamanho dos operandos é especificado com base em palavra-chaves que são adicionadas anteriormente ao operando. Na sintaxe AT&T o tamanho do operando é especificado por um sufixo adicionado a instrução, conforme tabela abaixo:

Sufixo

Tamanho

Palavra-chave equivalente no NASM

B

byte (8 bits)

byte

W

word (16 bits)

word

L

long/doubleword (32 bits)

dword

Q

quadword (64 bits)

qword

T

ten word (80 bits)

tword

Exemplos:

# AT&T               # Intel

movl $5, %eax        # mov dword eax, 5
movb $'A', (%ebx)    # mov byte [ebx], 'A'

Assim como o NASM consegue identificar o tamanho do operando quando é usado um registrador e a palavra-chave se torna opcional, o mesmo acontece no GAS e o sufixo também é opcional nesses casos.

Far jump e call

Na sintaxe Intel saltos e chamadas distantes são feitas com jmp far [etc] e call far [etc] respectivamente. Na sintaxe da AT&T se usa o prefixo L nessas instruções, ficando: ljmp e lcall.

Endereçamento

Exemplos com o seu equivalente na sintaxe da Intel:

# AT&T                       # Intel

mov my_var, %eax             # mov eax, [my_var]
mov 5(%ebx), %eax            # mov eax, [ebx + 5]
mov 5(%ebx, %esi), %eax      # mov eax, [ebx + esi + 5]
mov 5(%ebx, %esi, 4), %eax   # mov eax, [ebx + esi*4 + 5]

mov (, %esi, 4), %eax        # mov eax, [esi*4]
mov (%ebx), %eax             # mov eax, [ebx]

mov %es:(%ebx), %eax         # mov eax, [es:ebx]
mov %es:5(%ebx), %eax        # mov eax, [es:ebx + 5]

mov my_var(%rip), %rax       # mov rax, [rel my_var]

Como demonstrado no último exemplo o endereço relativo na sintaxe do GAS é feito explicitando RIP como base, enquanto na sintaxe do NASM isso é feito usando a palavra-chave rel.

Saltos

Na sintaxe da AT&T os saltos para endereços armazenados na memória devem ter um * antes do rótulo para indicar que o salto deve ocorrer para o endereço que está armazenado naquele endereço de memória. Sem o * o salto ocorre para o rótulo em si. Exemplo:

# AT&T               # Intel

jmp my_code          # jmp my_code
jmp *my_pointer      # jmp [my_pointer]

Saltos que especificam segmento e offset separam os dois valores por vírgula. Como em:

# AT&T               # Intel

jmp $1234, $5678     # jmp 1234:5678

Aprendendo a usar o GAS

As diretivas do GAS funcionam de maneira semelhante as diretivas do NASM com a diferença que todas elas são prefixadas por um ponto.

Comentários

No GAS comentários de múltiplas linhas podem ser escritos com /* e */ assim como em C. Comentários de uma única linha podem ser escritos com # ou //.

Pseudo-instruções de dados

Pseudo-instrução

Tipo do dado (tamanho em bits)

Equivalente no NASM

.byte

byte (8 bits)

db

.short

.hword

.word

word (16 bits)

dw

.long

.int

doubleword (32 bits)

dd

.quad

quadword (64 bits)

dq

.float

.single

Single-precision floating-point (32 bits)

dd

.double

Double-precision floating-point (64 bits)

dq

.ascii

.string

.string8

String (8 bits cada caractere)

db

.asciz

Mesmo que .ascii porém com um terminador nulo no final

-

.string16

String (16 bits cada caractere)

-

.string32

String (32 bits cada caractere)

-

.string64

String (64 bits cada caractere)

-

Exemplos:

msg1: .ascii "Hello World\0"
msg2: .asciz "Hello World"

value1: .byte 1, 2, 3, 4, 5
value2: .float 3.1415

Diretivas de seções e alinhamento

O GAS tem diretivas específicas para declarar algumas seções padrão. Conforme tabela:

GAS

Equivalente no NASM

.data

section .data

.bss

section .bss

.text

section .text

Porém ele também tem a diretiva .section que pode ser usada de maneira semelhante a section do NASM. Os atributos da seção porém são passados em formato de flags em uma string como segundo argumento. As flags principais são w para dar permissão de escrita e x para dar permissão de execução. Exemplos:

# GAS                         # NASM

.section .mysection, "wx"     # section .mysection write exec
.section .rodata              # section .rodata
.text                         # section .text
.section .text                # section .text

A diretiva .align pode ser usada para alinhamento dos dados. Você pode usá-la no início da seção para alinhar a mesma, conforme exemplo:

    .section .rodata
    .align 16

# Equivalente no NASM: section .rodata align=16

Usando sintaxe Intel

A diretiva .intel_syntax pode ser usada para habilitar a sintaxe da Intel para o GAS. Opcionalmente pode-se passar um parâmetro noprefix para desabilitar o prefixo % dos registradores.

Uma diferença importante da sintaxe Intel do GAS em relação ao NASM é que as palavra-chaves que especificam o tamanho do operando precisam ser seguidas por ptr, conforme exemplo abaixo:

    .intel_syntax noprefix
    .text
example:
    mov byte ptr [ebx], 7
    mov word ptr [ebx], 7
    mov dword ptr [ebx], 7
    mov qword ptr [ebx], 7
    ret

Exemplo de código na sintaxe AT&T

#include <stdio.h>

void assembly(float *array);

int main(void)
{
  float array[4];
  assembly(array);

  printf("%f, %f, %f, %f\n", array[0], array[1], array[2], array[3]);
  return 0;
}
    .section .rodata
    .align 16
    local_array: .float 1.23
                 .float 2.45
                 .float 3.67
                 .float 4.89

    .text
    .globl assembly
assembly:
    movaps local_array(%rip), %xmm5
    movaps %xmm5, (%rdi)
    ret
PreviousProgramando junto com CNextConvenção de chamada da System V ABI

Last updated 3 years ago

Was this helpful?

Na sintaxe Intel é bem intuitivo já que ele é escrito em formato de expressão matemática. Na sintaxe AT&T é um pouco mais confuso e segue o seguinte formato: segment:displacement(base, index, scale).

No NASM db, dw, dd, dq etc. que servem para despejar bytes no arquivo binário de saída. No GAS isso é feito usando as seguintes pseudo-instruções:

O exemplo abaixo é o mesmo apresentado no tópico sobre porém reescrito na sintaxe do GAS/AT&T:

o endereçamento
instruções de movimentação SSE
existem as pseudo-instruções