Como exportar símbolos de uma biblioteca compartilhada
-
09-09-2019 - |
Pergunta
Eu criei uma biblioteca compartilhada (*.so
) usando os arquivos de código *.o
objeto (código-fonte C) usando o compilador RVDS no Host Windows.
eu ligar este objeto compartilhado com um aplicativo (utilizando gcc
para o alvo ARM no host Linux) e obter um executável, que em correr gera falha de segmentação. (Eu sei que tenho de depurá-lo!)
Em vez de criar biblioteca compartilhada, se eu criar uma biblioteca estática com arquivos de origem mesmos, e então ligação com a aplicação, e em seguida, executar o aplicativo funciona bem como esperado.
Então, minhas perguntas são:
-
Eu preciso exportar símbolos (funções exportados para a aplicação) ou quaisquer outros símbolos, explicitamente, no meu arquivo de origem usando algumas construções para que ele funciona bem quando ligado a uma aplicação? O que é necessário e como posso fazer isso?
-
Como é compartilhada trabalho biblioteca ?, ou seja, vão os endereços onde as funções serão carregado e executado, será dada na biblioteca ser dado quando a biblioteca é criada. Como o aplicativo (
main()
) resolver os endereços onde as funções de biblioteca devem ser executadas? -
Como funciona uma biblioteca estática, ou seja, como é que esta especificação de endereço e resolver acontecer em caso de biblioteca estática?
Solução
Este é assim que funciona no Linux:
1) Não, você não precisa fazer nada. Você pode, no entanto, restringir a exportação variáveis ??com o argumento de linha de comando gcc -fvisibility
e explicitamente entradas bandeira exportados com o atributo visibilidade.
2) O executável terá uma tabela de todas as funções que importa (estas são todas as funções com visibilidade padrão). O carregador / vinculador irá escolher um endereço para carregar as bibliotecas de e para preencher esta tabela apenas antes de executar, as chamadas para essas funções são chamadas indiretas. (Note que isso vale para objetos compartilhados também)
3) vinculação estática é realizada em ligação em tempo (que é depois de compilar). Os endereços reais são substituídos na assembléia, e eles são chamadas directas.
Nota: Não é a coisa chamada PIC (código independente de posição). AFAIK, este lida com referências a dados / funções no mesmo objeto compartilhado, por isso a necessidade de vinculador não meio de substituição do código da biblioteca ao carregar a biblioteca, da mesma forma que o código não faz quaisquer referências absolutas à sua dados próprios. Você pode tentar experimentar com ele.
Outras dicas
-
Você não precisa de símbolos de exportação com
gcc
, já que exporta todos os símbolos por padrão; RVDS pode ou não pode fazer o mesmo, no entanto. Verifique se o seu RVDS documentação do compilador (tentar configurá-lo para ' Relocatable ELF ' output?) -
bibliotecas compartilhadas em Linux deve ser relocatable, como o endereço de base é determinado em tempo de execução. Gerando código independente de posição é ideal, uma vez que reduz a quantidade de trabalho necessário para mudar o local da biblioteca. Se sua biblioteca não é Relocatable ele irá acidente (em outras palavras, não tira informações de relocação de seus arquivos de objeto antes de fazer a biblioteca dinâmica). Os símbolos são resolvidos para endereços em tempo de execução após o endereço base é selecionado e referências internas são realocados.
-
Com bibliotecas estáticas, toda a resolução de símbolo, transferências e atribuição de endereços de carga acontece em tempo de compilação.
Meu único palpite seria que de alguma forma, o código de seu compilador é colocar para fora não é relocatable em tempo de execução. É um mistério para mim como isso poderia acontecer sem quebrar bibliotecas estáticas, bem como, embora ...
Se você está gerando uma biblioteca estática e biblioteca compartilhada diretamente do RVDS, uma opção seria tentar converter essa biblioteca estática para uma biblioteca compartilhada:
gcc -shared -o libfoo.so libfoo.a
Se isto ajudar, então compartilhada vinculador biblioteca de RVDS (ou a sua configuração) é provavelmente quebrado.
Você sabe alguma coisa sobre a causa do acidente?
Uma possibilidade se você estiver carregando a biblioteca compartilhada dinamicamente (por exemplo, via dlopen()
) é que você está assumindo que a biblioteca OK carregado quando isso não aconteceu, e, em seguida, está tentando executar funções através de ponteiros nulos.