Eu preciso otimizar o tamanho do meu executável severamente ( ARM
desenvolvimento) e notei que no meu esquema de compilação atual ( gcc
+ ld
) os símbolos não usados não estão sendo removidos.
O uso de arm-strip --strip-unneeded
para os executáveis / bibliotecas resultantes não altera o tamanho de saída do executável (não tenho ideia do motivo, talvez simplesmente não possa) .
Qual seria a maneira (se houver) de modificar meu pipeline de construção, de modo que os símbolos não utilizados sejam retirados do arquivo resultante?
Eu nem sequer penso nisso, mas meu ambiente incorporado atual não é muito "forte" e economizando ainda 500K
fora de 2M
resultados em um impulso muito agradável desempenho de carregamento.
Atualizar:
Infelizmente, a gcc
versão atual que uso não tem a -dead-strip
opção e o -ffunction-sections... + --gc-sections
for ld
não dá nenhuma diferença significativa para a saída resultante.
Estou chocado que isso se tornou um problema, porque eu tinha certeza que gcc + ld
deveria remover automaticamente os símbolos não utilizados (por que eles ainda têm que mantê-los?).
boost
bibliotecas, o.exe
arquivo resultante contém muitos arquivos objetos não usados e devido às especificações do meu tempo de execução incorporado atual , iniciar um10mb
aplicativo demora muito mais do que, por exemplo, iniciar um500k
aplicativo.Respostas:
Para o GCC, isso é realizado em duas etapas:
Primeiro compile os dados, mas diga ao compilador para separar o código em seções separadas dentro da unidade de tradução. Isso será feito para funções, classes e variáveis externas usando os dois sinalizadores de compilador a seguir:
Vincule as unidades de tradução usando o sinalizador de otimização do vinculador (isso faz com que o vinculador descarte as seções não referenciadas):
Portanto, se você tivesse um arquivo chamado test.cpp que tivesse duas funções declaradas, mas uma delas não fosse usada, você poderia omitir o não usado com o seguinte comando para gcc (g ++):
(Observe que -Os é um sinalizador de compilador adicional que diz ao GCC para otimizar o tamanho)
fonte
mingw
isso não funciona ao vincular estaticamente estaticamente libstdc ++ e libgcc com o sinalizador-static
. A opção do vinculador-strip-all
ajuda um pouco, mas ainda assim o executável gerado (ou dll) é cerca de 4 vezes maior do que o que o Visual Studio geraria. O que quero dizer é que não tenho controle sobre comolibstdc++
foi compilado. Deve haver umald
única opção.Para acreditar nessa thread , você precisa fornecer o
-ffunction-sections
e-fdata-sections
ao gcc, que colocará cada função e objeto de dados em sua própria seção. Então você dá e--gc-sections
ao GNU ld para remover as seções não utilizadas.fonte
Você vai querer verificar seus documentos para sua versão do gcc & ld:
No entanto, para mim (OS X gcc 4.0.1), acho isso para ld
E esta opção útil
Também há uma observação no gcc / g ++ man que certos tipos de eliminação de código morto são executados apenas se a otimização estiver habilitada durante a compilação.
Embora essas opções / condições possam não se aplicar ao seu compilador, sugiro que você procure algo semelhante em seus documentos.
fonte
mingw
.-dead_strip
não é umagcc
opção.Os hábitos de programação também podem ajudar; por exemplo, adicionar
static
funções que não são acessadas fora de um arquivo específico; use nomes mais curtos para os símbolos (pode ajudar um pouco, provavelmente não muito); use sempreconst char x[]
que possível; ... este artigo , embora fale sobre objetos compartilhados dinâmicos, pode conter sugestões que, se seguidas, podem ajudar a diminuir o tamanho da saída binária final (se seu destino for ELF).fonte
.so
no Linux), portanto, os nomes dos símbolos devem ser retidos para que APIs como octypes
módulo FFI do Python possam usá-los para procurar símbolos por nome em tempo de execução.A resposta é
-flto
. Você deve passá-lo para as etapas de compilação e link, caso contrário, ele não fará nada.Na verdade, funciona muito bem - reduziu o tamanho de um programa de microcontrolador que escrevi para menos de 50% do tamanho anterior!
Infelizmente, parecia um pouco bugado - tive casos de coisas que não foram construídas corretamente. Pode ter sido devido ao sistema de compilação que estou usando (QBS; é muito novo), mas em qualquer caso, eu recomendo que você apenas habilite-o para sua compilação final, se possível, e teste-a completamente.
fonte
-flto
eu não entendo o que ela faz nos bastidores.-flto
ele não compila cada arquivo para o assembly, ele os compila para o LLVM IR, e então o link final os compila como se estivessem todos em uma unidade de compilação. Isso significa que pode eliminar funções não utilizadas e não umas em linhastatic
e provavelmente outras coisas também. Consulte llvm.org/docs/LinkTimeOptimization.htmlEmbora não seja estritamente sobre símbolos, se for pelo tamanho - sempre compilar com os sinalizadores
-Os
e-s
.-Os
otimiza o código resultante para o tamanho mínimo do executável e-s
remove a tabela de símbolos e as informações de realocação do executável.Às vezes - se o tamanho pequeno for desejado - brincar com diferentes sinalizadores de otimização pode - ou não - ter significado. Por exemplo, alternar
-ffast-math
e / ou-fomit-frame-pointer
pode, às vezes, economizar até dezenas de bytes.fonte
-ffast-math
confusão em código C ++ totalmente compatível com os padrões, então eu nunca recomendaria.Parece-me que a resposta fornecida por Nemo é a correta. Se essas instruções não funcionarem, o problema pode estar relacionado à versão do gcc / ld que você está usando, como um exercício, compilei um programa de exemplo usando as instruções detalhadas aqui
Em seguida, compilei o código usando interruptores de remoção de código morto progressivamente mais agressivos:
Esses parâmetros de compilação e vinculação produziram executáveis de tamanho 8457, 8164 e 6160 bytes, respectivamente, a contribuição mais substancial proveniente da declaração 'strip-all'. Se você não puder produzir reduções semelhantes em sua plataforma, talvez sua versão do gcc não suporte esta funcionalidade. Estou usando gcc (4.5.2-8ubuntu4), ld (2.21.0.20110327) no Linux Mint 2.6.38-8-generic x86_64
fonte
strip --strip-unneeded
opera apenas na tabela de símbolos do seu executável. Na verdade, ele não remove nenhum código executável.As bibliotecas padrão alcançam o resultado desejado, dividindo todas as suas funções em arquivos de objetos separados, que são combinados usando
ar
. Se você então vincular o arquivo resultante como uma biblioteca (ou seja, dar a opção-l your_library
de ld), então ld incluirá apenas os arquivos objeto e, portanto, os símbolos que são realmente usados.Você também pode encontrar algumas das respostas a esta questão semelhante de uso.
fonte
Não sei se isso ajudará em sua situação atual, pois este é um recurso recente, mas você pode especificar a visibilidade dos símbolos de uma maneira global. Passar
-fvisibility=hidden -fvisibility-inlines-hidden
na compilação pode ajudar o vinculador a se livrar de símbolos desnecessários posteriormente. Se você estiver produzindo um executável (em oposição a uma biblioteca compartilhada), não há mais nada a fazer.Mais informações (e uma abordagem detalhada para, por exemplo, bibliotecas) estão disponíveis no wiki do GCC .
fonte
Do manual GCC 4.2.1, seção
-fwhole-program
:fonte
-flto
.Você pode usar strip binário no arquivo de objeto (por exemplo, executável) para retirar todos os símbolos dele.
Nota: ele muda o próprio arquivo e não cria uma cópia.
fonte