Pegue o ld para escolher a biblioteca correta

3

Estou tentando compilar um programa prog e vinculá-lo à versão 1.0.2 beta do OpenSSL, criada a partir da origem e instalada em /usr/local/ssl-1.0.2 . Em um sistema antigo usando 0.9.8, isso funciona sem muitos problemas. Em um sistema mais recente com o 1.0.1 instalado, isso requer um pouco mais de trabalho. Eu estou me perguntando por quê.

1) No Ubuntu 10.04, com o OpenSSL 0.9.8:

Aqui estão os passos que eu sigo para compilar e linkar com o 1.0.2.

$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto

= > Apenas 0.9.8 arquivos aparecem, então eu adiciono o caminho para os arquivos 1.0.2 ...

$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto

= >

 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0008000000008000) => /lib/i686/cmov/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0004000000000000) => /lib/i586/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0002000000000000) => /lib/i486/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6) => /lib/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6) => /usr/lib/libcrypto.so.0.9.8
 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so

E então eu posso compilar prog ...

$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

= >

    libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0x0083b000)

... e está corretamente ligado ao 1.0.2.

2) No Debian Wheezy, com o OpenSSL 1.0.1:

Mesmos passos, resultado diferente.

$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto

= >

 libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0

Da mesma forma, adiciono o caminho para 1.0.2 ...

$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto

= >

 libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so

Então eu tento compilar ...

$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

= >

    libcrypto.so.1.0.0 => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 (0xb7591000)

Mas aqui não está vinculado ao 1.0.2. O caminho da biblioteca em tempo de compilação está correto (especificado com -L , gcc falharia de outra forma, pois algumas funções usadas em prog são específicas de 1.0.2), mas não em tempo de execução.

3) Como fazê-lo funcionar em Wheezy

Com ou sem a execução de ldconfig /usr/local/ssl-1.0.2/lib :

$ gcc -o prog ... -Wl,--rpath=/usr/local/ssl-1.0.2/lib -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

= >

    libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0xb7592000)

Como alternativa, execute export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib antes de executar gcc .

O que eu gostaria de saber

Usando LD_DEBUG=libs ./prog como sugerido por mr.spuratic, descobri que os caminhos foram procurados em /etc/ld.so.cache . Eu abri o arquivo e descobri que a ordem em que são pesquisados corresponde à saída de ldconfig -p .

Então, a pergunta atual é:

  • Por que o arquivo 1.0.2 fica em cima da lista do ldconfig em 1), mas não em 2)? Aleatoriedade pura? Confusão devido a arquivos 1.0.1 e 1.0.2 terem o mesmo sufixo? ("1.0.0")

Ou, dito de forma diferente,

  • Por que os sinalizadores adicionados em 3) não são necessários em 1)?
por Peniblec 18.06.2014 / 11:54

2 respostas

5

Há três coisas que você precisa resolver ao compilar / vincular em um pacote não padrão:

  • cabeçalhos (geralmente CFLAGS )
  • caminho da biblioteca em tempo de compilação (geralmente LDFLAGS )
  • caminho da biblioteca de tempo de execução ( rpath via LDFLAGS , LD_RUN_PATH , LD_LIBRARY_PATH ou ld.so.conf )

Você não disse o que é prog , então não posso saber o quão bem comportada é sua configuração (ou se usa o autoconf?), eu já vi muitos que realizam as duas primeiras etapas de maneira confiável.

Durante o estágio de link, a ordem do caminho da biblioteca é relevante, presumindo que você esteja usando o conjunto de ferramentas GNU (gcc & binutils), provavelmente você verá o que está acontecendo configurando CFLAGS antes de configure (ou possível no Makefile diretamente):

export CFLAGS="-Wl,-t"

Isso passa a opção -t trace para o vinculador. Você pode precisar adicionar V=1 ou VERBOSE=1 ao comando make se somente as linhas "CC" e "LD" forem emitidas durante a criação.

Em tempo de execução, você pode ver o que ld.so tenta definir com cuidado LD_DEBUG , por exemplo

LD_DEBUG=libs ./myprog

(ou tente valores de files ou symbols para mais detalhes)

Para especificar todos os três parâmetros corretamente no tempo de compilação, você deve ser capaz de fazer:

  • export CFLAGS="-I/usr/local/ssl-1.0.2/include"
  • export LDFLAGS="-L/usr/local/ssl-1.0.2/lib -R/usr/local/ssl-1.0.2/lib"

reconfigure / recompile.

Você está usando --openssldir em vez do mais convencional --prefix (eu recomendo o último e também usando apenas make install_sw se você não precisa das 1000 páginas man & symlinks que uma instalação padrão oferece ). Isso pode ser parte do problema. Por algum motivo, as bibliotecas .so que você mostra são conhecidas por ld.so e não têm um sufixo de versão (por exemplo, .so.1.0.2 ), um " make install " adequado deve ter configurado isso para você (via link-shared target no principal Makefile ).

A opção -R instrui o vinculador a incorporar um RPATH na saída executável da biblioteca OpenSSL específica, para que não precise depender do padrão que o vinculador de tempo de execução ( ld.so ) normalmente forneceria. Você pode modificar os binários existentes com chrpath .

Isso é mais ou menos equivalente a exportar LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib . Você pode ler mais sobre o RPATH e o RUNPATH relacionado aqui: link

Como último recurso, você poderia construir o OpenSSL sem "compartilhado" ou com "noshared", isso forneceria bibliotecas estáticas que não terão esse problema (mas podem ter outros problemas, por exemplo, para uso no ELF .so , causando problemas PIC / PIE)

Com base nos detalhes atualizados, acredito que o problema é que 1.0.1 e 1.0.2beta definem o sufixo da versão .so (SONAME) como 1.0.0. No primeiro sistema com apenas 0.9.8 isso não causa problemas; no segundo com 1.0.1 e 1.0.2 ambos versionados como 1.0.0, é o "primeiro jogo ganha" baseado na ordem ld.so.{conf,d} . Lembre-se, ld o vinculador de tempo de compilação é um programa diferente para ld.so do vinculador de tempo de execução e pode ter um comportamento diferente (geralmente resultando em erros de símbolo ou pior, como você viu).

$ cd /usr/local/src/openssl/openssl/1.0.2beta1
$ readelf -a libssl.so | grep SONAME
0x0000000e (SONAME)                     Library soname: [libssl.so.1.0.0]

$ cat verchk.c
int main(int argc, char *argv[]) {
    printf("build: %s\n",OPENSSL_VERSION_TEXT);
    printf("run  : %s\n",SSLeay_version(SSLEAY_VERSION));
    return 0;
}

$ gcc -Wall  -I/usr/local/src/openssl/openssl-1.0.2-beta1/include \
    -Wl,-rpath /usr/local/src/openssl/openssl-1.0.2-beta1/ \
    -o verchk /usr/local/src/openssl/openssl-1.0.2-beta1/libcrypto.so verchk.c

$ ./verchk
build: OpenSSL 1.0.2-beta1 24 Feb 2014
run  : OpenSSL 1.0.2-beta1 24 Feb 2014

$ grep SHLIB_M...R= Makefile
SHLIB_MAJOR=1
SHLIB_MINOR=0.0

Atualizar O OpenSSL-1.1 fez algumas alterações no nível da API, o código acima falhará na compilação com cabeçalhos v1.1 e bibliotecas antigas ( undefined reference to 'OpenSSL_version' ).

SSLeay_version() agora está reprovado e (dependendo de OPENSSL_API_COMPAT ) pode ser #define -d para a função de API adequada OpenSSL_version() .

    
por 18.06.2014 / 13:38
0

O caminho da nova lib em um dos arquivos dentro de /etc/ld.so.conf.d ? Próxima execução: -

#ldconfig -v

para reconstruir o cache. Se você for rápido, deverá ver a nova biblioteca na longa lista impressa (ou canalizar para grep ou less )

Talvez o caminho já estivesse no primeiro servidor, mas não no segundo?

    
por 18.06.2014 / 13:34