---
title: "Syscalls Linux com Zig: Guia Completo para Chamadas de Sistema"
url: "https://ziglang.com.br/tutoriais/zig-syscalls-linux/"
markdown_url: "https://ziglang.com.br/tutoriais/zig-syscalls-linux.MD"
description: "Aprenda a fazer syscalls Linux diretamente com Zig. Entenda como o kernel funciona, invoque read, write, open e close, e crie wrappers seguros com tratamento de erros. Tutorial completo em portugues."
date: "2026-02-21"
author: ""
---

# Syscalls Linux com Zig: Guia Completo para Chamadas de Sistema

Aprenda a fazer syscalls Linux diretamente com Zig. Entenda como o kernel funciona, invoque read, write, open e close, e crie wrappers seguros com tratamento de erros. Tutorial completo em portugues.


Syscalls sao a interface fundamental entre seus programas e o kernel do sistema operacional. Toda operacao que envolve recursos do sistema — abrir arquivos, alocar memoria, criar processos, enviar dados pela rede — passa por uma syscall. Neste primeiro artigo da serie **Programacao de Sistemas com Zig**, vamos explorar como Zig facilita o uso direto de syscalls Linux, oferecendo uma experiencia muito mais segura e ergonomica do que C.

> Este artigo assume que voce ja tem familiaridade com a sintaxe basica de Zig. Se voce esta comecando, confira primeiro a serie [Zig para Iniciantes](/tutoriais/zig-para-iniciantes/).

## O Que Sao Syscalls?

Quando um programa em user space precisa interagir com hardware ou recursos gerenciados pelo kernel, ele nao pode fazer isso diretamente. Em vez disso, ele faz uma **chamada de sistema** (syscall), que e uma requisicao ao kernel para executar uma operacao privilegiada.

O fluxo e o seguinte:

1. O programa coloca o numero da syscall em um registrador (rax no x86_64)
2. Os argumentos sao colocados em registradores especificos (rdi, rsi, rdx, r10, r8, r9)
3. A instrucao `syscall` e executada, transferindo controle ao kernel
4. O kernel executa a operacao e retorna o resultado em rax

Em C, voce tipicamente usa wrappers da libc como `read()`, `write()`, `open()`. Em Zig, voce tem acesso direto as syscalls atraves do modulo `std.os.linux` e tambem pode usar a standard library de forma mais ergonomica.

## Syscalls Diretas em Zig

Zig permite invocar syscalls diretamente sem depender da libc. Isso e particularmente util para sistemas embarcados, binarios estaticos minimos ou quando voce precisa de controle total.

### Exemplo: write syscall direta

```zig
const std = @import("std");
const linux = std.os.linux;

pub fn main() void {
    const mensagem = "Ola direto do kernel!\n";
    // syscall write: fd=1 (stdout), buffer, tamanho
    const resultado = linux.syscall3(
        .write,
        1, // file descriptor 1 = stdout
        @intFromPtr(mensagem.ptr),
        mensagem.len,
    );

    if (resultado < 0) {
        // Erro na syscall
        std.debug.print("Erro na syscall write: {d}\n", .{resultado});
    }
}
```

Observe que estamos chamando `linux.syscall3` diretamente, passando o numero da syscall (`.write`) e seus tres argumentos. O "3" em `syscall3` indica o numero de argumentos.

### Entendendo os Numeros de Syscall

Zig define todas as syscalls Linux como um enum em `std.os.linux.SYS`. Voce pode usar nomes simbolicos em vez de numeros magicos:

```zig
const linux = std.os.linux;

// Em vez de usar numeros magicos:
// const SYS_write = 1;  // Estilo C

// Zig usa um enum tipado:
const syscall_write = linux.SYS.write;    // = 1 no x86_64
const syscall_read = linux.SYS.read;      // = 0 no x86_64
const syscall_open = linux.SYS.open;      // = 2 no x86_64
const syscall_close = linux.SYS.close;    // = 3 no x86_64
```

Isso torna o codigo portavel entre arquiteturas, ja que os numeros de syscall podem variar entre x86_64, aarch64, etc.

## A Standard Library: O Caminho Recomendado

Embora syscalls diretas sejam educativas, para codigo de producao a standard library de Zig oferece wrappers muito mais seguros e ergonomicos. Esses wrappers cuidam do tratamento de erros, conversao de tipos e compatibilidade entre plataformas.

### Abrindo e Lendo Arquivos

```zig
const std = @import("std");

pub fn main() !void {
    // Abrir arquivo para leitura
    const arquivo = try std.fs.cwd().openFile("/etc/hostname", .{});
    defer arquivo.close();

    // Ler conteudo em um buffer
    var buffer: [1024]u8 = undefined;
    const bytes_lidos = try arquivo.read(&buffer);

    const conteudo = buffer[0..bytes_lidos];
    std.debug.print("Hostname: {s}", .{conteudo});
}
```

Compare com o equivalente em C:

```c
// Versao C - mais verbosa e propensa a erros
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int fd = open("/etc/hostname", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    char buffer[1024];
    ssize_t n = read(fd, buffer, sizeof(buffer));
    if (n == -1) {
        perror("read");
        close(fd);  // Facil esquecer!
        return 1;
    }

    buffer[n] = '\0';  // Facil esquecer!
    printf("Hostname: %s", buffer);
    close(fd);  // Facil esquecer!
    return 0;
}
```

Em Zig, `defer arquivo.close()` garante que o arquivo sera fechado nao importa o que aconteca. O operador `try` propaga erros automaticamente. Nao ha risco de esquecer o `close()` ou de nao verificar erros.

### Escrevendo em Arquivos

```zig
const std = @import("std");

pub fn main() !void {
    // Criar ou truncar arquivo
    const arquivo = try std.fs.cwd().createFile("saida.txt", .{});
    defer arquivo.close();

    // Escrever conteudo
    try arquivo.writeAll("Primeira linha\n");
    try arquivo.writeAll("Segunda linha\n");

    // Usar writer formatado
    const writer = arquivo.writer();
    try writer.print("Valor: {d}\n", .{42});
    try writer.print("Data: {s}\n", .{"2026-02-21"});
}
```

## Syscalls Essenciais para Programadores Zig

Vamos explorar as syscalls mais importantes que todo programador de sistemas precisa conhecer.

### open, read, write, close — O Quarteto Fundamental

Estas quatro syscalls formam a base de toda operacao de I/O no Linux. Tudo e um arquivo no Unix: dispositivos, pipes, sockets e arquivos regulares sao todos manipulados com essas syscalls.

```zig
const std = @import("std");
const posix = std.posix;

pub fn main() !void {
    // open: abre um file descriptor
    const fd = try posix.open("/tmp/teste_syscall.txt", .{
        .ACCMODE = .WRONLY,
        .CREAT = true,
        .TRUNC = true,
    }, 0o644);
    defer posix.close(fd);

    // write: escreve bytes no file descriptor
    const dados = "Escrito via posix.open!\n";
    const bytes_escritos = try posix.write(fd, dados);
    std.debug.print("Bytes escritos: {d}\n", .{bytes_escritos});
}
```

### mmap — Mapeamento de Memoria

`mmap` e uma das syscalls mais poderosas do Linux. Ela mapeia arquivos ou memoria anonima diretamente no espaco de enderecamento do processo.

```zig
const std = @import("std");
const posix = std.posix;

pub fn main() !void {
    const arquivo = try std.fs.cwd().openFile("dados.bin", .{});
    defer arquivo.close();

    const stat = try arquivo.stat();
    const tamanho = stat.size;

    // Mapear arquivo na memoria
    const mapeado = try posix.mmap(
        null,
        tamanho,
        posix.PROT.READ,
        .{ .TYPE = .SHARED },
        arquivo.handle,
        0,
    );
    defer posix.munmap(mapeado);

    // Agora podemos acessar o arquivo como um slice de bytes
    const bytes: []const u8 = @as([*]const u8, @ptrCast(mapeado))[0..tamanho];
    std.debug.print("Primeiros 100 bytes: {s}\n", .{bytes[0..@min(100, bytes.len)]});
}
```

`mmap` e extremamente eficiente para arquivos grandes porque o kernel carrega as paginas sob demanda (lazy loading), e multiplos processos podem compartilhar a mesma memoria fisica.

### ioctl — Controle de Dispositivos

`ioctl` e a syscall "coringa" do Linux, usada para operacoes especificas de dispositivos que nao se encaixam no modelo read/write.

```zig
const std = @import("std");
const posix = std.posix;
const linux = std.os.linux;

const TIOCGWINSZ = 0x5413;

const Winsize = extern struct {
    ws_row: u16,
    ws_col: u16,
    ws_xpixel: u16,
    ws_ypixel: u16,
};

pub fn obterTamanhoTerminal() !Winsize {
    var ws: Winsize = undefined;
    const resultado = linux.ioctl(
        std.io.getStdOut().handle,
        TIOCGWINSZ,
        @intFromPtr(&ws),
    );
    if (resultado != 0) return error.IoctlFailed;
    return ws;
}

pub fn main() !void {
    const tamanho = try obterTamanhoTerminal();
    std.debug.print("Terminal: {d} linhas x {d} colunas\n", .{
        tamanho.ws_row,
        tamanho.ws_col,
    });
}
```

## Tratamento de Erros em Syscalls

Uma das maiores vantagens de Zig sobre C para programacao de sistemas e o tratamento de erros. Em C, voce precisa verificar manualmente o valor de retorno de cada syscall e consultar `errno`. Em Zig, o sistema de error unions torna isso natural e impossivel de esquecer.

### Padrao em C (propenso a erros)

```c
int fd = open("arquivo.txt", O_RDONLY);
if (fd == -1) {
    // Programador pode esquecer esta verificacao
    perror("open");
    return 1;
}
// Se esquecer o if, o programa continua com fd = -1
```

### Padrao em Zig (seguro por design)

```zig
const std = @import("std");

pub fn main() !void {
    // Se open falhar, o erro e propagado automaticamente com try
    const arquivo = try std.fs.cwd().openFile("arquivo.txt", .{});
    defer arquivo.close();

    // Ou trate o erro explicitamente
    const arquivo2 = std.fs.cwd().openFile("outro.txt", .{}) catch |err| {
        std.debug.print("Erro ao abrir: {}\n", .{err});
        return;
    };
    defer arquivo2.close();
}
```

O compilador Zig **exige** que voce lide com cada possivel erro. Voce nao pode simplesmente ignorar o retorno de uma funcao que pode falhar. Isso elimina uma classe inteira de bugs que sao comuns em programas C.

## Criando Wrappers Seguros

Para projetos maiores, e uma boa pratica criar wrappers que adicionam contexto e logging as operacoes de syscall.

```zig
const std = @import("std");

const SysError = error{
    PermissaoNegada,
    ArquivoNaoEncontrado,
    SemEspaco,
    ErroDesconhecido,
};

pub fn lerArquivoCompleto(
    allocator: std.mem.Allocator,
    caminho: []const u8,
) ![]u8 {
    const arquivo = std.fs.cwd().openFile(caminho, .{}) catch |err| {
        std.log.err("Falha ao abrir '{s}': {}", .{ caminho, err });
        return switch (err) {
            error.FileNotFound => SysError.ArquivoNaoEncontrado,
            error.AccessDenied => SysError.PermissaoNegada,
            else => SysError.ErroDesconhecido,
        };
    };
    defer arquivo.close();

    const conteudo = try arquivo.readToEndAlloc(allocator, 10 * 1024 * 1024);
    std.log.info("Lido {d} bytes de '{s}'", .{ conteudo.len, caminho });
    return conteudo;
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const conteudo = try lerArquivoCompleto(allocator, "/etc/os-release");
    defer allocator.free(conteudo);

    std.debug.print("{s}\n", .{conteudo});
}
```

## Comparacao: Zig vs C para Syscalls

| Aspecto | C | Zig |
|---------|---|-----|
| **Verificacao de erros** | Manual, facil de esquecer | Obrigatoria pelo compilador |
| **Limpeza de recursos** | Manual (close, free) | Automatica com `defer` |
| **Portabilidade** | Depende da libc | Pode compilar sem libc |
| **Seguranca de tipos** | Fraca (void*, int para tudo) | Forte (enums, error unions) |
| **Buffer overflows** | Faceis de causar | Verificacao em runtime |
| **Cross-compilation** | Complexa (toolchains) | `zig build -Dtarget=...` |

## Exercicios Praticos

### Exercicio 1: Informacoes do Sistema
Crie um programa que leia e exiba o conteudo de `/proc/cpuinfo` e `/proc/meminfo`, extraindo o modelo do processador e a memoria total.

### Exercicio 2: Copia de Arquivos
Implemente uma funcao que copie um arquivo para outro usando buffers de 4096 bytes, exibindo o progresso durante a copia.

### Exercicio 3: Listagem de Diretorios
Use a standard library para listar todos os arquivos de um diretorio, mostrando nome, tamanho e permissoes.

---

## Proximo Artigo

No proximo artigo, vamos nos aprofundar em [operacoes de file system](/tutoriais/zig-sistemas-operacionais/artigo-2-file-system-operations/), explorando manipulacao de diretorios, permissoes, file locking e memory-mapped files.

### Conteudo Relacionado

- [Zig para Programadores C](/tutoriais/zig-para-programadores-c/) — Transicao de C para Zig
- [Gerenciamento de Memoria em Zig](/tutoriais/gerenciamento-de-memoria-zig/) — Allocators e ponteiros
- [Tratamento de Erros em Zig](/tutoriais/tratamento-de-erros-em-zig/) — Error unions em profundidade
- [Zig e Interoperabilidade com C](/tutoriais/zig-c-interoperabilidade/) — Chamando codigo C de Zig

---

*Tem duvidas sobre syscalls em Zig? Deixe um comentario ou entre em contato com a comunidade Zig Brasil.*
