---
title: "Go dynamic TLS mira c-shared no Linux arm64"
url: "https://golang.com.br/novidades/go-dynamic-tls-c-shared-arm64/"
markdown_url: "https://golang.com.br/novidades/go-dynamic-tls-c-shared-arm64.MD"
description: "Proposta de Go dynamic TLS melhora bibliotecas c-shared e c-archive no Linux arm64, especialmente em ambientes Musl e containers."
date: "2026-05-18"
author: "Go Brasil"
---

# Go dynamic TLS mira c-shared no Linux arm64

Proposta de Go dynamic TLS melhora bibliotecas c-shared e c-archive no Linux arm64, especialmente em ambientes Musl e containers.


TL;DR: uma nova proposta de design no repositório `golang/proposal` descreve suporte a **general dynamic TLS** no toolchain do Go. A mudança não adiciona API à linguagem nem muda código Go comum, mas pode remover uma dor importante para quem empacota Go como biblioteca `c-shared` ou `c-archive` no Linux arm64, especialmente em sistemas baseados em Musl. O objetivo é permitir que o runtime encontre o ponteiro da goroutine atual de forma compatível com carregamento dinâmico, sem depender de atalhos como `LD_PRELOAD`.

## O problema que a proposta ataca

Quando código Go atravessa a fronteira com C, o runtime precisa preservar informações internas para voltar ao mundo Go com segurança. Uma dessas informações é o ponteiro para a goroutine atual, normalmente chamado de `g` dentro do runtime. Em alguns caminhos de cgo, race detector e runtime assembly, esse valor fica associado a TLS, ou *thread-local storage*.

O Go já lida com modelos de TLS como *local exec* e *initial exec*. Eles funcionam bem em vários cenários tradicionais, mas são mais restritivos quando um binário precisa carregar bibliotecas compartilhadas de forma dinâmica. A proposta aponta um caso concreto: bibliotecas Go criadas com `-buildmode=c-shared` podem ter problemas em ambientes Linux arm64 com Musl, a libc comum em imagens Alpine e sistemas minimalistas.

Na prática, isso interessa a quem faz Go virar uma peça dentro de outro sistema: plugins nativos, integrações com runtimes em C, SDKs distribuídos como `.so`, ou artefatos `c-archive` que depois entram em uma biblioteca compartilhada maior. Para uma API HTTP Go pura, compilada como binário estático com `CGO_ENABLED=0`, nada muda.

## O que é general dynamic TLS

TLS é o mecanismo que permite ter uma variável por thread. Em C, isso costuma aparecer como `__thread` ou `_Thread_local`. No runtime do Go, o detalhe é mais baixo nível: assembly precisa carregar o endereço certo a partir do registrador de thread e das relocations geradas pelo linker.

O modelo **general dynamic** é mais flexível para bibliotecas compartilhadas carregadas em tempo de execução. Em vez de assumir que o endereço TLS já pode ser resolvido de forma direta, o código usa uma sequência compatível com o linker dinâmico. No AArch64, a proposta fala em gerar relocations ELF do tipo TLSDESC e em adicionar suporte de relocation no assembler/linker do Go.

Um comando de build afetado ficaria no território abaixo:

```bash
GOOS=linux GOARCH=arm64 go build -buildmode=c-shared -o libminhaapi.so ./cmd/lib
```

Hoje, dependendo da libc, do linker externo e de como essa `.so` é carregada, o artefato pode exigir arranjos específicos de deploy. Com TLS dinâmico geral, a intenção é que o `cmd/go` escolha automaticamente o modelo mais adequado nos alvos suportados.

## O que mudaria no toolchain

A proposta não expõe uma nova função em `runtime`, `unsafe` ou qualquer pacote da biblioteca padrão. A mudança é interna ao toolchain, mas envolve várias peças:

- uma opção de assembler `-tls=IE|LE|GD`;
- definição `TLS_GD` para selecionar macros alternativas no assembly do runtime;
- nova relocation `R_ARM64_TLS_GD`;
- emissão de relocations TLSDESC para linkers externos;
- escolha automática pelo `cmd/go` para casos suportados.

O escopo inicial é deliberadamente estreito: `GOOS=linux`, `GOARCH=arm64`, `-buildmode=c-shared` e `-buildmode=c-archive`. A proposta também assume linkagem externa para esse caminho, seguindo a realidade de integração com bibliotecas C e linkers do sistema.

Esse recorte é importante. Não é uma promessa de que todos os alvos, arquiteturas e modos de build passarão a usar general dynamic TLS. É uma correção de infraestrutura para um ponto onde o modelo atual atrapalha interoperabilidade.

## Por que desenvolvedores Go deveriam se importar

A maioria dos times Go não vai tocar nisso diretamente. Mas a existência da proposta mostra uma direção importante: o projeto Go continua investindo nos casos em que Go precisa conviver com toolchains nativos, containers minimalistas e bibliotecas compartilhadas.

Esse é um tema menos visível que generics, `slog` ou melhorias de GC, mas pesa em produção. Se você distribui uma biblioteca Go para ser chamada por Python, Ruby, Node, Java, C ou outro runtime via FFI, pequenos detalhes de ABI, TLS e linker viram problemas reais de instalação. Um artefato que funciona no Debian com glibc pode falhar em Alpine com Musl; uma `.so` que carrega via `LD_PRELOAD` pode não carregar quando o host usa `dlopen` normalmente.

Para times que adotam containers enxutos, essa diferença também aparece em decisões de base image. Muitos tutoriais recomendam `CGO_ENABLED=0` para simplificar deploy, inclusive em cenários de Docker. Isso continua sendo uma ótima escolha quando a aplicação é um serviço Go autônomo. Mas quando o objetivo é integrar com C ou gerar uma biblioteca compartilhada, desligar cgo não é uma opção: o produto é justamente a fronteira Go/C.

## O que observar antes de depender disso

Como a issue pública ainda aparece no fluxo de proposta, trate o design como sinal de direção, não como recurso disponível em uma versão estável. Detalhes de flag, arquitetura suportada e comportamento automático do `cmd/go` podem mudar antes de chegar a um release.

Se esse problema afeta seu time hoje, o melhor caminho é isolar um caso mínimo de build e carregamento: mesma arquitetura, mesma libc, mesmo linker e mesmo modo de carregamento usado em produção. Isso facilita acompanhar a issue, testar protótipos quando houver builds disponíveis e reportar problemas com evidência concreta.

Também vale evitar conclusões amplas demais. A proposta não torna cgo “grátis”, não resolve todas as diferenças entre glibc e Musl e não muda as recomendações para serviços Go comuns. Ela ataca um ponto específico: suporte correto a TLS dinâmico geral para que bibliotecas Go compartilhadas tenham menos restrições no Linux arm64.

## Saiba mais

- [Proposta: Go general dynamic TLS](https://raw.githubusercontent.com/golang/proposal/master/design/71953-go-dynamic-tls.md)
- [Issue golang/go#71953](https://github.com/golang/go/issues/71953)
- [Tutorial de Docker com Go](/tutoriais/go-docker-container/)
- [Deploy de Go na AWS com Linux arm64](/tutoriais/go-aws-deploy/)
