Liaison avec une ancienne version de libc pour fournir une plus grande couverture d’applications

Les binarys Linux sont généralement liés dynamicment à la bibliothèque système principale (libc). Cela garde l’encombrement mémoire du fichier binary assez petit mais les fichiers binarys qui dépendent des bibliothèques les plus récentes ne fonctionneront pas sur les systèmes plus anciens. Inversement, les fichiers binarys liés aux anciennes bibliothèques fonctionneront parfaitement sur les derniers systèmes.

Par conséquent, pour assurer une bonne couverture de notre application lors de la dissortingbution, nous devons déterminer la plus ancienne libc que nous pouvons prendre en charge et lier notre binary à cela.

Comment devrions-nous déterminer la version la plus ancienne de la libc à laquelle nous pouvons nous connecter?

    Déterminez quels symboles de votre exécutable créent la dépendance sur la version non désirée de glibc.

    $ objdump -p myprog ... Version References: required from libc.so.6: 0x09691972 0x00 05 GLIBC_2.3 0x09691a75 0x00 03 GLIBC_2.2.5 $ objdump -T myprog | fgrep GLIBC_2.3 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3 realpath 

    Regardez dans la bibliothèque dépendante pour voir s’il existe des symboles dans les anciennes versions avec lesquels vous pouvez établir un lien:

     $ objdump -T /lib/libc.so.6 | grep -w realpath 0000000000105d90 g DF .text 0000000000000021 (GLIBC_2.2.5) realpath 000000000003e7b0 g DF .text 00000000000004bf GLIBC_2.3 realpath 

    Nous avons de la chance!

    Demandez la version de GLIBC_2.2.5 dans votre code:

     #include  #include  __asm__(".symver realpath,realpath@GLIBC_2.2.5"); int main () { realpath ("foo", "bar"); } 

    Notez que GLIBC_2.3 n’est plus nécessaire:

     $ objdump -p myprog ... Version References: required from libc.so.6: 0x09691a75 0x00 02 GLIBC_2.2.5 $ objdump -T myprog | grep realpath 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realpath 

    Pour plus d’informations, voir http://www.trevorpounds.com/blog/?p=103 .

    Malheureusement, la solution de @ Sam ne fonctionne pas bien dans ma situation. Mais à sa manière, j’ai trouvé ma propre façon de résoudre ce problème.

    Ceci est ma situation:

    J’écris un programme C ++ en utilisant le framework Thrift (c’est un middleware RPC). Je préfère le lien statique au lien dynamic, donc mon programme est lié à libthrift.a statiquement au lieu de libthrift.so . Cependant, libthrift.a est lié dynamicment à la glibc et depuis que mon libthrift.a est construit sur mon système avec glibc 2.15, mon libthrift.a utilise memcpy de la version 2.14 ( memcpy@GLIBC_2.14 ) fournie par la glibc 2.15.

    Mais le problème est que nos machines serveur ne disposent que de la version 2.5 de glibc qui ne contient que memcpy@GLIBC_2.2.5 . C’est beaucoup moins que memcpy@GLIBC_2.14 . Donc, bien sûr, mon programme serveur ne peut pas fonctionner sur ces machines.

    Et j’ai trouvé cette solusion:

    1. Utiliser .symver pour obtenir la référence à memcpy@GLIBC_2.2.5 .

    2. Écrivez ma propre fonction __wrap_memcpy qui appelle simplement memcpy@GLIBC_2.2.5 directement.

    3. Lorsque vous liez mon programme, ajoutez l’ option -Wl, – wrap = memcpy à gcc / g ++.

    Le code impliqué dans les étapes 1 et 2 est ici: https://gist.github.com/nicky-zs/7541169

    Pour ce faire, vous pouvez utiliser le script suivant pour créer une liste de tous les symboles plus récents dans votre GLIBC que dans une version donnée (définie à la ligne 2). Il crée un fichier glibc.h (nom de fichier défini par l’argument de script) qui contient toutes les déclarations .symver nécessaires. Vous pouvez ensuite append -include glibc.h à votre CFLAGS pour vous assurer qu’il sera capté partout dans votre compilation.

    Ceci est suffisant si vous n’utilisez aucune bibliothèque statique compilée sans l’inclusion ci-dessus. Si vous le faites, et que vous ne voulez pas recomstackr, vous pouvez utiliser objcopy pour créer une copie de la bibliothèque avec les symboles renommés dans les anciennes versions. La deuxième à la dernière ligne du script crée une version de votre système libstdc++.a qui sera liée aux anciens symboles glibc. Ajouter -L. (ou -Lpath/to/libstdc++.a/ ) fera que votre programme liera statiquement libstdc ++ sans lier un tas de nouveaux symboles. Si vous n’en avez pas besoin, supprimez les deux dernières lignes et la ligne printf ... redeff .

     #!/bin/bash maxver=2.9 headerf=${1:-glibc.h} set -e for lib in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 libresolv.so.2 librt.so.1; do objdump -T /usr/lib/$lib done | awk -v maxver=${maxver} -vheaderf=${headerf} -vredeff=${headerf}.redef -f <(cat <<'EOF' BEGIN { split(maxver, ver, /\./) limit_ver = ver[1] * 10000 + ver[2]*100 + ver[3] } /GLIBC_/ { gsub(/\(|\)/, "",$(NF-1)) split($(NF-1), ver, /GLIBC_|\./) vers = ver[2] * 10000 + ver[3]*100 + ver[4] if (vers > 0) { if (symvertext[$(NF)] != $(NF-1)) count[$(NF)]++ if (vers <= limit_ver && vers > symvers[$(NF)]) { symvers[$(NF)] = vers symvertext[$(NF)] = $(NF-1) } } } END { for (s in symvers) { if (count[s] > 1) { printf("__asm__(\".symver %s,%s@%s\");\n", s, s, symvertext[s]) > headerf printf("%s %s@%s\n", s, s, symvertext[s]) > redeff } } } EOF ) sort ${headerf} -o ${headerf} objcopy --redefine-syms=${headerf}.redef /usr/lib/libstdc++.a libstdc++.a rm ${headerf}.redef 

    La glibc 2.2 est une version minimum assez courante. Cependant, trouver une plate-forme de construction pour cette version peut ne pas être sortingvial.

    Une meilleure direction est probablement de penser au système d’exploitation le plus ancien que vous souhaitez prendre en charge et d’en tirer parti.