Ссылка на старую версию libc, чтобы обеспечить больший охват приложения - PullRequest
63 голосов
/ 27 октября 2010

Двоичные файлы Linux обычно динамически связаны с базовой системной библиотекой (libc). Это сохраняет объем памяти двоичного файла довольно маленьким, но двоичные файлы, которые зависят от новейших библиотек, не будут работать на старых системах. И наоборот, двоичные файлы, связанные со старыми библиотеками, будут успешно работать на последних системах.

Поэтому, чтобы обеспечить хорошее покрытие нашего приложения во время распространения, нам нужно выяснить самый старый libc, который мы можем поддерживать, и связать наш двоичный файл с этим.

Как определить самую старую версию libc, на которую мы можем ссылаться?

Ответы [ 4 ]

77 голосов
/ 12 мая 2011

Определите, какие символы в вашем исполняемом файле создают зависимость от нежелательной версии 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://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103.

9 голосов
/ 19 ноября 2013

К сожалению, решение @ Сэма не работает в моей ситуации.Но, по его мнению, я нашел свой собственный способ решить эту проблему.

Это моя ситуация:

Я пишу программу на C ++ с использованием фреймворка Thrift (это промежуточное ПО RPC).Я предпочитаю статическую ссылку динамической ссылке, поэтому моя программа статически связана с libthrift.a вместо libthrift.so .Однако libthrift.a динамически связан с glibc, и, поскольку мой libthrift.a собран в моей системе с glibc 2.15, мой libthrift.a использует memcpy версии 2.14 (memcpy@GLIBC_2.14), предоставляемый glibc 2.15.

Но проблема в том, что на наших серверных компьютерах есть только версия 2.5 glibc, которая имеет толькоmemcpy@GLIBC_2.2.5.Это намного ниже, чем memcpy@GLIBC_2.14.Поэтому, конечно, моя серверная программа не может работать на этих машинах.

И я нашел это решение:

  1. Использование .symver для получения ссылки на memcpy@GLIBC_2.2.5.

  2. Напишите мою собственную __ wrap_memcpy функцию, которая просто вызывает memcpy@GLIBC_2.2.5 напрямую.

  3. При связывании моей программы добавьте параметр -Wl, - wrap = memcpy к gcc / g ++.

код, включенный в шаги 1 и 2, находится здесь: https://gist.github.com/nicky-zs/7541169

8 голосов
/ 16 сентября 2016

Чтобы сделать это более автоматизированным способом, вы можете использовать следующий скрипт, чтобы создать список всех символов, которые являются более новыми в вашей GLIBC, чем в данной версии (установлено в строке 2). Он создает файл glibc.h (имя файла задается аргументом script), который содержит все необходимые объявления .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
3 голосов
/ 27 октября 2010

glibc 2.2 - довольно распространенная минимальная версия.Однако найти платформу сборки для этой версии может быть нетривиально.

Вероятно, лучшее направление - подумать о самой старой ОС, которую вы хотите поддерживать, и построить на ней.

...