Atualizado: 16/11/2025

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

Como Usar Bibliotecas Padrão do Linux em Assembly NASM

O sistema operacional Linux vem com um conjunto de bibliotecas compartilhadas, principalmente as da linguagem C, que podemos utilizar em nossos programas Assembly para acessar funcionalidades de alto nível.

As bibliotecas compartilhadas do sistema geralmente começam com o prefixo lib, têm a extensão .so e estão localizadas em diretórios como /usr/lib. Em sistemas x86-64, a biblioteca C principal, libc.so, pode ser encontrada em /usr/lib/x86_64-linux-gnu. Esta biblioteca contém funções essenciais como printf, scanf, malloc, entre outras.

Utilizando a Função printf

Vamos criar um programa app.asm que usa a função printf da libc para imprimir uma mensagem no console.

global _start
extern printf   ; Declara a função printf como externa

section .data
    message: db "Hello programicio.com", 10, 0

section .text
_start:
    lea rdi, [rel message]      ; 1º parâmetro de printf: endereço da string
    xor rax, rax                ; Indica que nenhum argumento de ponto flutuante é usado
    call printf                 ; Chama a função printf

    mov rax, 60
    syscall

Neste código, declaramos printf como externa e a chamamos, passando o endereço da string no registrador RDI, conforme a convenção de chamada do System V ABI.

Linkando com a Biblioteca C

Para conectar nosso programa com a biblioteca libc.so, usamos a opção -l do linker ld. Essa opção é seguida pelo nome da biblioteca, omitindo o prefixo lib e a extensão .so. Portanto, para linkar com libc.so, usamos -lc.

  1. Montar o arquivo-objeto:

    $ nasm -felf64 app.asm -o app.o
  2. Linkar com libc:

    $ ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -lc app.o -o app

    O comando instrui o linker a usar o loader dinâmico e a procurar por símbolos não resolvidos (como printf) na biblioteca c (que corresponde a libc.so).

Agora, podemos executar o programa:

$ ./app
Hello programicio.com

Podemos usar a ferramenta ldd para verificar que nosso aplicativo agora depende da libc.so:

$ ldd app
    linux-vdso.so.1 (0x00007ffc129e1000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f354a205000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f354a43b000)

A segunda linha confirma a dependência da biblioteca C.

Usando Bibliotecas em um Executável PIE

Se estivermos criando um executável independente de posição (PIE), devemos nos lembrar de usar o endereçamento relativo às tabelas PLT e GOT para acessar funções e variáveis externas.

Vamos adaptar o código app.asm para ser um PIE:

global _start
extern printf

section .data
    message: db "Hello programicio.com", 10, 0

section .text
_start:
    lea rdi, [rel message]
    xor rax, rax
    call printf wrt ..plt       ; Chamada via PLT

    mov rax, 60
    syscall

A única mudança é adicionar wrt ..plt à chamada. A compilação também requer a flag -pie:

$ nasm -felf64 app.asm -o app.o
$ ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -pie -lc app.o -o app
$ ./app
Hello programicio.com

Acessando Variáveis Globais de Bibliotecas

Além de funções, as bibliotecas também podem exportar variáveis globais. Por exemplo, a libc exporta um ponteiro stdout que representa o fluxo de saída padrão. Vamos usá-lo com a função fprintf, que tem a seguinte assinatura em C: int fprintf(FILE *stream, const char *format, ...)

global _start
extern fprintf
extern stdout   ; Declara o objeto global stdout como externo

section .data
    message: db "Hello World", 10, 0

section .text
_start:
    mov rdi, [rel stdout wrt ..got]   ; Carrega o endereço do ponteiro stdout via GOT
    mov rdi, [rdi]                    ; De-referencia para obter o valor do ponteiro (o stream)
    lea rsi, [rel message]            ; 2º parâmetro: endereço da string
    xor rax, rax
    call fprintf wrt ..plt            ; Chama fprintf via PLT

    mov rax, 60
    syscall

Neste exemplo:

  1. Declaramos fprintf e stdout como externos.
  2. Usamos a GOT para obter o endereço da variável global stdout.
  3. Como stdout é um ponteiro para uma estrutura FILE, nós de-referenciamos o endereço para obter o valor real do ponteiro, que é o que fprintf espera como primeiro argumento.
  4. Chamamos fprintf via PLT.

O processo de compilação é o mesmo do exemplo PIE anterior.


Resumo

  • É possível chamar funções de bibliotecas padrão do Linux (como a libc.so) a partir de programas Assembly.
  • Para linkar uma biblioteca compartilhada, use a opção -l<nome> do linker ld (por exemplo, -lc para libc.so).
  • Ao criar executáveis independentes de posição (PIE), as chamadas a funções externas devem ser feitas via PLT (wrt ..plt).
  • O acesso a variáveis globais exportadas por bibliotecas em um PIE deve ser feito via GOT (wrt ..got).
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