Atualizado: 18/10/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Chamadas de Sistema no Linux e a Instrução SYSCALL | Assembly NASM

Em sistemas operacionais modernos, muitos recursos — como dispositivos de entrada e saída — não estão diretamente acessíveis para aplicações comuns. Para acessar esses recursos e outras funcionalidades internas do sistema, o programa executa uma chamada de sistema (system call).

Durante essa operação, a execução da aplicação é temporariamente interrompida, e o controle é transferido para o núcleo do sistema operacional. O kernel verifica se o pedido é válido e se o processo tem permissão para executá-lo. Após realizar a tarefa solicitada, o controle retorna à aplicação.

Por exemplo, para encerrar corretamente um programa em Linux, é necessário chamar a função do sistema identificada pelo número 60.

global _start

section .text
_start:
    mov rdi, 22     ; código de status de saída
    mov rax, 60     ; número da função do sistema (exit)
    syscall          ; chamada de sistema

A instrução syscall executa a função do sistema cujo número foi carregado no registrador RAX. Cada função possui um número próprio; o kernel identifica qual operação realizar com base nesse número.


Registradores e Parâmetros

Além do número da função, algumas chamadas de sistema exigem parâmetros adicionais, que são enviados nos seguintes registradores, nesta ordem:

rdi, rsi, rdx, r10, r8, r9

Se a função requer apenas um parâmetro, ele é colocado em rdi. Se forem dois, o segundo é colocado em rsi, e assim por diante.

A função exit, por exemplo, precisa de um único argumento: o código de status, colocado em rdi.

A instrução syscall também altera os registradores rcx e r11.

  • rcx armazena o endereço da próxima instrução (valor anterior de rip).
  • r11 guarda o valor antigo de rflags.

Se o programa faz uso desses registradores, é importante salvá-los antes da chamada (por exemplo, empilhando-os com push) para evitar perda de dados.

Após a execução, o valor retornado pela função é armazenado em rax.

Uma tabela completa e atualizada das chamadas de sistema do Linux x86-64 está disponível na documentação oficial do kernel (Linux kernel syscall tables).

Tempo em Unix

Os sistemas baseados em Unix medem o tempo em segundos desde o início da época Unix (00:00 de 1º de janeiro de 1970). A chamada de sistema time, de número 201 (0xc9), retorna o tempo atual. Ela requer um parâmetro: o endereço de uma variável de 64 bits onde o tempo será armazenado.

Quando a função é executada com sucesso, rax contém o mesmo valor do ponteiro fornecido em rdi.

Trecho do código-fonte da função time no kernel:

SYSCALL_DEFINE1(time, __kernel_old_time_t __user *, tloc)
{
    __kernel_old_time_t i = (__kernel_old_time_t)ktime_get_real_seconds();

    if (tloc) {
        if (put_user(i,tloc))
            return -EFAULT;
    }
    force_successful_syscall_return();
    return i;
}

Exemplo de programa em NASM que aguarda aproximadamente 5 segundos antes de encerrar:

global _start

section .data
curtime dq 0        ; variável para armazenar o tempo

section .text
_start:
    ; obtém o tempo inicial
    mov rax, 0xc9      ; número da função time
    mov rdi, curtime   ; endereço da variável curtime
    syscall

    mov rdx, [curtime] ; armazena o tempo atual em rdx
    add rdx, 5         ; adiciona 5 segundos

timeloop:
    mov rax, 0xc9      ; verifica o tempo novamente
    mov rdi, curtime
    syscall
    cmp qword [curtime], rdx
    jb timeloop         ; enquanto não atingir o tempo desejado, repete

exit:
    mov rdi, 22         ; código de status
    mov rax, 60         ; chamada de saída (exit)
    syscall

Nesse exemplo, o programa obtém o tempo inicial e entra em um laço que consulta o tempo atual repetidamente, saindo apenas após o acréscimo de 5 segundos.

Escrita em Arquivo ou Console

Uma das chamadas de sistema mais utilizadas é write, responsável por escrever dados em um arquivo ou em um fluxo de saída. Em Linux, praticamente tudo é tratado como arquivo: dispositivos, terminais, e até mesmo o teclado e o monitor.

Quando um arquivo é aberto, o kernel associa a ele um número chamado descritor de arquivo (file descriptor). Os três descritores padrão de todo processo são:

  • 0: entrada padrão (stdin) — teclado
  • 1: saída padrão (stdout) — console
  • 2: saída de erro (stderr) — mensagens de erro

A função write possui o número 1 e recebe três parâmetros:

ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)

O registrador rdi contém o descritor do destino (por exemplo, 1 para o console). rsi armazena o endereço do texto a ser escrito, e rdx define o tamanho do texto.

Exemplo que exibe uma mensagem no console:

global _start

section .data
message db "Hello www.programicio.com", 10
len equ $ - message      ; tamanho da string

section .text
_start:
    mov rax, 1           ; número da função write
    mov rdi, 1           ; descritor de saída padrão
    mov rsi, message     ; endereço da mensagem
    mov rdx, len         ; comprimento da mensagem
    syscall

    mov rdi, rax         ; quantidade de bytes realmente escritos
    mov rax, 60          ; chamada de saída
    syscall

Após a execução de syscall, o número de bytes efetivamente escritos é retornado em rax. No exemplo, esse valor é transferido para rdi antes do encerramento do programa.

Compilação e execução no Linux:

nasm -f elf64 hello.asm -o hello.o
ld hello.o -o hello
./hello
Hello www.programicio.com
echo $?
30

O código acima imprime a mensagem no terminal e retorna o valor 30, que corresponde ao número de bytes escritos.


Resumo

  • Chamadas de sistema permitem que programas interajam com o kernel.
  • A instrução syscall executa funções identificadas por números específicos armazenados em rax.
  • Parâmetros são enviados nos registradores rdi, rsi, rdx, r10, r8 e r9.
  • rcx e r11 são alterados durante a execução e devem ser preservados quando necessário.
  • Exemplos comuns incluem exit (encerramento), time (obtenção de tempo) e write (escrita em arquivo ou console).
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com