HeadlinesBriefing favicon HeadlinesBriefing.com

Otimização pilha trampolim funções aninhadas GCC

Hacker News •
×

Otimização de Pilha Trampolim para Funções Aninhadas no GCC. Chamada Indireta de Funções Aninhadas no GCC Sem Pilha Executável. Martin Uecker, 2026-08-29.

Discutimos da última vez como se pode usar funções aninhadas no GCC e Clang para callbacks sem exigir uma pilha executável. Mas e se for necessário suportar versões mais antigas do GCC? Claro, pode-se simplesmente aceitar uma pilha executável, mas também é possível evitar isso com um truque. GCC: Funções Aninhadas e Trampolins.

Vamos discutir primeiro como o GCC suporta obter o endereço de uma função aninhada. Nosso exemplo de brinquedo sem o uso das novas macros é mostrado abaixo. No x86_64, o assembly gerado coloca um trampolim na pilha e o invoca imediatamente através da função baz inline.

O trampolim é uma curta sequência de código que carrega o registrador de frame estático para uma estrutura na pilha que contém as variáveis capturadas da função pai e então salta para a função local. Se alguém traduzir as constantes -17591, -17847 e -1864106167 de volta para instruções de assembly, obtém-se o seguinte código x86_64: movq $bar.0, %r11, movq $frame, %r10, jump *%r11. Tanto a cadeia estática quanto o endereço de código são constantes imediatas usadas por instruções de movimento no código do trampolim.

Em vez de usar o endereço do trampolim para chamar a função, podemos extrair o endereço de código e a cadeia estática do trampolim e usá-los com a função built-in __builtin_call_with_static_chain para chamar a função local diretamente. Assim, podemos usar a leitura desses dois valores de ponteiro de um trampolim como mecanismo de fallback em versões mais antigas do GCC. As desvantagens são que um trampolim ainda é criado, o compilador ainda não pode desvirtualizar a chamada indireta, e a pilha ainda será marcada como executável.

Então, o que foi ganho? Como nunca invocamos realmente o trampolim, podemos tornar a pilha não-executável novamente com o seguinte comando, o que pelo menos aborda as preocupações de segurança deste recurso. patchelf --clear-execstack program. Esta ideia é implementada na minha biblioteca experimental, noplate, onde um ponteiro largo é construído a partir do endereço de código e da cadeia estática. Trampolins como Descritores de Função.

Há outra ideia que considero digna de exploração: também se poderia usar o próprio trampolim como descritor de função. Em vez de extrair a cadeia estática e o ponteiro de código onde o trampolim é criado, simplesmente passamos o endereço do trampolim como de costume. Mas em todos os lugares onde poderíamos chamar o trampolim, primeiro verificamos se o ponteiro aponta para um trampolim, e então extraímos o endereço de código e a cadeia estática para chamar a função aninhada diretamente usando __builtin_call_with_static_chain.

Em certo sentido, poderíamos dizer que, em vez de invocar o trampolim, estamos interpretando o código do trampolim no local da chamada usando um interpretador super simples que só pode interpretar esta sequência de código específica e que é tão simples que...