Por que (e como) tenho (aparentemente!) símbolos duplicados em minhas bibliotecas compartilhadas?

Por que (e como) tenho (aparentemente!) símbolos duplicados em minhas bibliotecas compartilhadas?

Acontece que eu precisava descobrir quais símbolos foram exportados por qual biblioteca a partir de uma lista simples de símbolos de biblioteca compartilhada exportados. Havia símbolos suficientes (20 ou mais) na lista para que eu não cruzasse manualmente cada um deles.

Descobri que isso nm -A -D -f sysv <library-name>parecia produzir resultados úteis - eu poderia procurar linhas contendo FUNCque também listassem um endereço na segunda coluna. Então executei esse comando em tudo /usr/lib, redirecionando-o para um arquivo.

Para minha surpresa, a verificação de integridade no script que fiz para analisar o arquivo relatou que havia símbolos duplicados! Após investigação e descobriu quebibliotecas pareciam estar exportando símbolos duplicados?!?

Verifiquei isso usando alguns scripts de shell e consegui transformar os comandos que usei nisso (tecnicamente) uma linha:

readlink -f /lib/* /usr/lib/* \
  | grep -F .so. | sort | uniq \
  | while read x; do nm -A -D -f sysv $x; done \
  | grep FUNC | cut -d'|' -f1 | sort -g | uniq -c | sort -g \
  | sed -n '/^ \+1/!{s/^ \+[0-9]\+ \+//p}' | sed 's/ //g' \
  | tr '\n' '\v' \
  | sed ':1;s/\([^ ]\+\):\([^\v$]\+\)\v\1:/\1:\2|/g;t1' \
  | tr '\v' '\n' \
  | while IFS=: read -a x; do \
     nm -A -D -f sysv "${x[0]}" | grep ":\\(${x[1]//|/\\|}\\).*FUNC"; \
  done

O comando acima fará com que seu disco procure por um curto período de tempo. Você pode dividi-lo em pedaços que redirecionam para arquivos temporários, se desejar. Tambéma saída será muito ampla(~150 colunas).

Inicialmente executei o script original em um chroot do Debian Squeeze no qual estava trabalhando, mas por curiosidade executei o script acima em meu sistema host para descobrir se o chroot de alguma forma não estava lógico.

Bem... o chroot relatou pouco mais de 90 duplicatas, mas meu sistema host (Arch) aparentemente tem cerca de 267.

O comando funciona pela nmsaída do grepping, então os resultados são um pouco barulhentos, mas fica assim:

/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access|00043700|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access|000436c0|   T  |              FUNC|0000003c|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_access_mask|000458f0|   T  |              FUNC|00000058|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size|000432a0|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size|00043260|   T  |              FUNC|0000003c|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_max|00044ff0|   T  |              FUNC|0000003c|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_max|00045030|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_min|000453c0|   T  |              FUNC|00000037|     |.text
/usr/lib/libasound.so.2.0.0:snd_pcm_hw_params_get_buffer_size_min|00045380|   T  |              FUNC|0000003c|     |.text

Observe como existem dois de cada símbolo.O endereço é diferente, sim, mas... pensei que a vinculação dinâmica funcionasse pelo nome do símbolo, e foi isso. Minha confusão é agravada pelo fato de que (se você rolar para a direita na listagem acima) os símbolos são todos do tipo FUNCe da .textseção.

Estou postando isso para saber que mágica interessante está acontecendo aqui. (Já que meu sistema está funcionando...)

Se alguém tiver alguma boa idéia de onde eu possa despejar cerca de 600 linhas de texto - o Pastebin não parece mais estar na moda e eu não uso o GitHub - ficarei feliz em compartilhar o resultado completo.

Responder1

Os símbolos aparecem duplicados porque as informações fornecidas por nmestão incompletas: os símbolos em questão são versionados. Você pode ver isso com objdump -T:

0000000000059d00 g    DF .text  0000000000000044 (ALSA_0.9)   snd_pcm_hw_params_get_access
0000000000056040 g    DF .text  000000000000004b  ALSA_0.9.0rc4 snd_pcm_hw_params_get_access

ou opção nmde --with-symbol-versions:

/usr/lib/x86_64-linux-gnu/libasound.so.2.0.0:snd_pcm_hw_params_get_access|0000000000059d00|   T  |              FUNC|0000000000000044|     |.text@ALSA_0.9
/usr/lib/x86_64-linux-gnu/libasound.so.2.0.0:snd_pcm_hw_params_get_access|0000000000056040|   T  |              FUNC|000000000000004b|     |.text@@ALSA_0.9.0rc4

Os binários são vinculados a uma versão específica do símbolo e obterão a versão correta no momento do link. Isso permite que as APIs sejam alteradas, preservando a compatibilidade com versões anteriores.

informação relacionada