Связывание со старой версией libc для обеспечения большего охвата приложений
двоичные файлы Linux обычно динамически связаны с основной системной библиотекой (libc). Это сохраняет объем памяти двоичного файла довольно небольшим, но двоичные файлы, которые зависят от последних библиотек, не будут работать на старых системах. И наоборот, двоичные файлы, связанные со старыми библиотеками, будут успешно работать на последних системах.
поэтому, чтобы обеспечить хорошее покрытие нашего приложения во время распространения, нам нужно выяснить, какой самый старый libc мы можем поддерживать и связывать наши двоичный против этого.
Как мы должны определить самую старую версию libc, на которую мы можем ссылаться?
4 ответа:
выясните, какие символы в исполняемом файле создают зависимость от нежелательной версии 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
посмотрите в зависящей от библиотеки, чтобы увидеть, есть ли какие-либо символы в более старых версиях, которые вы можете связать с:
$ 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
нам повезло!
запрос версии от
GLIBC_2.2.5
в коде:#include <limits.h> #include <stdlib.h> __asm__(".symver realpath,realpath@GLIBC_2.2.5"); int main () { realpath ("foo", "bar"); }
обратите внимание, что GLIBC_2. 3 больше не требуется:
$ 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
дополнительную информацию см. http://www.trevorpounds.com/blog/?p=103.
к сожалению, решение @Sam не работает хорошо в моей ситуации. Но в соответствии с его способом, я нашел свой собственный способ решить эту проблему.
Это моя ситуация:
Я пишу программу на C++ с использованием Thrift framework (это промежуточное ПО RPC). Я предпочитаю статическую ссылку динамической ссылке, поэтому моя программа связана с libthrift.а статически вместо libthrift.so. однако,libthrift.а динамически связан с glibc, и так как мой libthrift.а строится на моей системе с glibc 2.15, my libthrift.а использует memcpy по версии 2.14(memcpy@GLIBC_2.14) библиотеку glibc 2.15.
но проблема в том, что наши серверные машины имеют только версию 2.5 glibc, которая имеет только memcpy@GLIBC_2.2.5. Это намного ниже, чем memcpy@GLIBC_2.14. Поэтому, конечно, моя серверная программа не может работать на этих машинах.
И Я нашел это решение:
использование .symver для получения ссылки на memcpy@GLIBC_2.2.5.
напиши мой собственный __оберните_функции memcpy функция, которая просто называет memcpy@GLIBC_2.2.5 напрямую.
при связывании моей программы, добавить - Wl,--wrap=memcpy опция для gcc / g++.
код, участвующий в шагах 1 и 2 здесь: https://gist.github.com/nicky-zs/7541169
чтобы сделать это более автоматизированным способом, вы можете использовать следующий скрипт для создания списка всех символов, которые являются более новыми в вашем GLIBC, чем в данной версии (установить в строке 2). Он создает
glibc.h
файл (имя файла, заданное аргументом скрипта), который содержит все необходимые.symver
декларации. Затем вы можете добавить-include glibc.h
к вашим CFLAGS, чтобы убедиться, что он будет подобран везде в вашей компиляции.этого достаточно, если вы не используете статические библиотеки, которые были компилируется без вышеуказанного включения. Если вы это сделаете, и вы не хотите перекомпилировать, вы можете использовать
objcopy
создать копию библиотеки с символами, переименованными в старые версии. Вторая нижняя строка скрипта создает версию вашей системыlibstdc++.a
это будет связано со старыми символами glibc. Добавление-L.
(или-Lpath/to/libstdc++.a/
) сделает вашу программу статически связать libstdc++ без связывания в кучу новых символов. Если вам это не нужно, удалите последние две строки и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