Pular para conteúdo

Manipulando strings em assembly x86-64

Nesta atividade, vamos manipular strings usando assembly GNU para Linux x86-64. Os programas são montados e executados nativamente no Linux, não é mais necessário usar o QEMU para emular o processador.

Exemplo

O programa minuscula.s lê uma string da entrada padrão, converte as letras de A a Z para minúsculas e imprime o resultado:

    .section .bss
    .lcomm buffer, 128

    .section .text
    .globl _start
_start:
    # read(0, buffer, 128)
    mov $0, %eax              # syscall read (Linux x86-64)
    mov $0, %edi              # fd = 0 (stdin)
    lea buffer(%rip), %rsi    # endereço do buffer
    mov $128, %edx            # tamanho máximo
    syscall
    mov %rax, %r12            # quantidade de bytes lidos

    # Converter somente letras A-Z em minúsculas
    lea buffer(%rip), %r13    # ponteiro para o buffer
    mov %r12, %r14            # contador de bytes
loop:
    test %r14, %r14
    jz done                   # termina quando todos os bytes forem processados
    movzbl (%r13), %eax       # lê o próximo byte
    cmp $'A', %al
    jb next                   # se < 'A', ignora
    cmp $'Z', %al
    ja next                   # se > 'Z', ignora
    or $0x20, %al             # ativa o bit 5: maiúscula -> minúscula
    mov %al, (%r13)           # grava o byte convertido
next:
    inc %r13
    dec %r14
    jmp loop
done:
    # write(1, buffer, nbytes)
    mov $1, %eax              # syscall write (Linux x86-64)
    mov $1, %edi              # fd = 1 (stdout)
    lea buffer(%rip), %rsi
    mov %r12, %rdx            # quantidade de bytes lidos
    syscall

    # exit(0)
    mov $60, %eax             # syscall exit (Linux x86-64)
    xor %edi, %edi
    syscall
  • O buffer de 128 bytes fica na seção .bss.
  • Em Linux x86-64, o número da syscall é passado em rax; os argumentos ficam em rdi, rsi, rdx, r10, r8 e r9. A instrução syscall solicita o serviço ao kernel.
  • read usa o número 0, e o total de bytes lidos retorna em rax. O exemplo guarda esse valor em r12 para usá-lo no laço e na impressão.
  • O laço percorre os bytes com r13 como ponteiro e r14 como contador. As comparações jb e ja ignoram caracteres fora do intervalo ASCII A-Z.
  • As letras minúsculas estão 32 posições depois das maiúsculas na tabela ASCII. or $0x20, %al ativa o bit correspondente e o resultado é gravado no buffer.
  • write usa o número 1; exit usa o número 60.

O código usa a sintaxe AT&T do GNU assembler: registradores levam %, valores imediatos levam $ e a ordem dos operandos é origem, destino.

Agora é a sua vez!

  1. Usando este programa como exemplo, complete maiuscula.s para converter as letras minúsculas para maiúsculas.
  2. Complete inverte.s para inverter a string sem modificar os caracteres.

Montagem e execução

No Linux x86-64, instale o GNU Binutils se necessário e execute os testes:

./setup.sh
./run.sh

Para testar somente um programa: ./tests/run.sh minuscula. O runner monta com as --64, liga com ld -m elf_x86_64 e executa o binário diretamente no Linux. Os testes de maiuscula e inverte passam depois que os exercícios forem implementados.