Por que ao carregar um arquivo SO ele anexa uma versão ao final?

3

Eu uso o CMake e o Ninja para criar um executável de teste meu escrito em C ++. Eu uso o gcc 4.8. Eu estou no Ubuntu 14.

Eu corro CMake para configurar os scripts de construção ninja, então eu corro ninja para construir. Eu especifico os arquivos libcrypto.so e outros arquivos openssl *.so como dependências de destino no script CMake.

Ao executar o executável, recebo o seguinte erro:

error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared object file: No such file or directory

Eu tenho meu arquivo libcrypto.so ao lado do executável de teste:

-rw-r--r-- 1 robert domain users 1796847 Apr 20 15:43 libboost_wave.so
-rw-r--r-- 1 robert domain users  410916 Apr 20 15:43 libboost_wserialization.so
-rw-r--r-- 1 robert domain users 2251519 Apr 21 11:28 libcrypto.so
-rw-r--r-- 1 robert domain users  701627 Apr 20 15:43 libEGL.so
-rw-r--r-- 1 robert domain users 4255871 Apr 20 15:43 libGLES_CM.so
-rw-r--r-- 1 robert domain users 7550551 Apr 20 15:43 libGLESv2.so
-rw-r--r-- 1 robert domain users  949113 Apr 17 14:34 libsqlite.so
-rw-r--r-- 1 robert domain users  496298 Apr 21 11:28 libssl.so
-rwxr-xr-x 1 robert domain users 3099250 Apr 21 11:30 Test_UI_String*

(O executável que estou executando é chamado Test_UI_String )

O CMake está configurado para produzir bibliotecas compartilhadas ao lado de executáveis, porque em outras plataformas como o Windows (onde eu estou mais familiarizado com o desenvolvimento) os arquivos DLL precisam estar ao lado do EXE para serem encontrados e carregados.

Estou confuso sobre o porquê de ter anexado 1.0.0 ao final do arquivo da biblioteca. Ele deve estar procurando por ele sem um número de versão no final, já que quando eu vinculei a dependência, ele tinha o mesmo nome que o libcrypto.so faz agora no diretório mostrado acima.

Eu gostaria de entender melhor o comportamento aqui, no entanto, minha pergunta principal é basicamente sobre como fazer isso funcionar como planejado (Encontre as dependências da biblioteca que estão localizadas no mesmo diretório que o executável).

    
por void.pointer 21.04.2015 / 18:38

1 resposta

1

Quando o vinculador gera um executável (ou outra biblioteca compartilhada), ele procura por bibliotecas solicitadas usando -l prefixando lib e sufixando .so com o nome. Por exemplo, se você solicitar -lcrypto , ele pesquisará libcrypto.so .

Após a biblioteca ser encontrada, o linker lê um metadado da biblioteca chamado seu soname. O soname é então gravado no executável que está sendo construído e esse é o nome que será usado para pesquisar a mesma biblioteca novamente em tempo de execução. O soname pode, é claro, ser diferente do nome sob o qual a biblioteca foi encontrada na hora do link.

O caso de uso para esse recurso é a capacidade de ter várias versões incompatíveis de uma biblioteca instalada no sistema ao mesmo tempo. Aqui está como é geralmente usado.

Primeiro, deixe-me descrever o que aconteceria na ausência dessa convenção:

Os cabeçalhos de desenvolvimento ( .h files) são acoplados a uma versão específica da biblioteca, e o arquivo .so contém essa versão também:

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so

Um aplicativo myapp foi compilado contra essa versão da biblioteca e carrega /usr/lib/libmylibrary.so no tempo de execução.

Mais tarde, a biblioteca é atualizada para uma nova versão. O arquivo .h e .so foi substituído pela nova versão. Infelizmente, a nova versão tem uma ABI incompatível.

Agora, quando myapp é executado, ele trava ou exibe um comportamento indefinido porque foi compilado em uma versão com uma ABI, mas carregou uma versão diferente em tempo de execução.

O que acontece com a convenção do soname:

A biblioteca é instalada da seguinte forma:

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.1
/usr/lib/libmylibrary.so.1

E /usr/lib/libmylibrary.so.1 embutiu o mesmo soname libmylibrary.so.1 .

Quando myapp é criado, ele localiza /usr/lib/libmylibrary.so , mas o vinculador segue o symlink e, na verdade, carrega /usr/lib/libmylibrary.so.1 . Além disso, o soname libmylibrary.so.1 é o que realmente é gravado dentro de myapp . Em tempo de execução, myapp carrega /usr/lib/libmylibrary.so.1 diretamente, ignorando o link simbólico.

Mais tarde, a biblioteca é atualizada para uma nova versão com uma ABI incompatível. O arquivo .h e .so foi substituído pela nova versão. Um novo arquivo libmylibrary.so.2 aparece. O libmylibrary.so.1 da versão antiga é deixado em paz.

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.2
/usr/lib/libmylibrary.so.1
/usr/lib/libmylibrary.so.2

Agora, quando myapp é executado, continua a carregar libmylibrary.so.1 e ainda funciona conforme o esperado. Mas se outros aplicativos novos forem instalados ou o myapp for recompilado, o link simbólico será seguido e a nova versão será usada.

O problema que você está vendo é que, quando seu aplicativo foi vinculado, o vinculador encontrou uma biblioteca que tinha o nome de usuário libcrypto.so.1.0.0 dentro dele.

Sua cópia de libcrypto.so foi gerada com um soname se libcrypto.so.1.0.0 ?

Outra possibilidade, bastante provável aqui, é que sua cópia de libcrypto.so não tenha um soname, mas o linker realmente encontrou e usou a versão system de libcrypto.so (do OpenSSL ) e é aí que fica o soname.

    
por 23.04.2015 / 02:21