2010-10-27 3 views
57

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

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

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

ответ

65

Определите, какие символы в исполняемом файле создают зависимость от нежелательной версии 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,[email protected]_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.

+6

Я бы также добавил, что часто есть только один или два символа, вызывающих зависимость от новой версии glibc, поэтому, если вы, как я, вы беспокоитесь, вам придется перечислить сотни символов, чтобы удалить зависимость, вы не будете. – Malvineous

+2

dietlibc также стоит посмотреть. –

+0

Или если вы можете связать статически (т. Е. Ваш код не является плагином и не будет использовать плагины), вы также можете посмотреть на musl-libc. Я часто обнаружил, что статически связанные программы с musl-libc меньше, чем их динамически связанные glibc-аналоги. – 0xC0000022L

3

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

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

+2

Имеет смысл, я просто надеясь на сочные низкие висящие плоды, которые я мог бы вырвать из ветвей возможности :-) –

+0

2.4 Linux Standard Base 4.0 (с 2006 года), 2,2 от 2000 ... –

+0

А? http://www.gnu.org/software/libc/ говорит, что glibc * 2.17 *, выпущенный 2012-12-25, является последней версией. Как 2.2 может быть общим минимумом? – musiphil

8

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

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

Я пишу программу на C++ с использованием рамок бережливости (что это RPC промежуточного слоя). Я предпочитаю статическую ссылку на динамическую ссылку, поэтому моя программа связана с libthrift.a статически вместо libthrift.so. Однако libthrift.a динамически связана с glibc, и так как мой libthrift.a построен на моей системе с GLibC 2.15, мой libthrift.a использует тетсру версии 2.14 ([email protected]_2.14), предоставленный glibc 2.15.

Но проблема в том, что наши серверные машины имеют только версию glibc 2.5, которая имеет только [email protected]_2.2.5. Он намного ниже [email protected]_2.14. Поэтому, конечно, моя серверная программа не может работать на этих машинах.

И я нашел этот solusion:

  1. Использование .symver получить реф к [email protected]_2.2.5.

  2. Написать свой собственный __wrap_memcpy функцию, которая просто вызывает [email protected]_2.2.5 непосредственно.

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

Код участвует в пунктах 1 и 2 здесь: https://gist.github.com/nicky-zs/7541169

+1

Проблема, по-видимому, связана с '_FORTIFY_SOURCE', которая по умолчанию равна 1 в новых версиях GCC на определенных уровнях оптимизации. При этом некоторые из функций маскируются. Для меня undefining и впоследствии переопределить его на 0 делает вышеупомянутое решение работать (GCC 4.8.4). – 0xC0000022L

7

Чтобы сделать это в более автоматизированным способом, вы можете использовать следующий скрипт, чтобы создать список всех символов, которые являются более новыми, в ваш 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,%[email protected]%s\");\n", s, s, symvertext[s]) > headerf 
     printf("%s %[email protected]%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 
+0

Почему 'sort'? – Otheus

+0

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

+0

Это решение 'objcopy --redefine-syms' на самом деле не работает, и потребовалось Мне нужно время, чтобы узнать почему. objcopy пытается выполнить замену соответствия строк для заданных символов, но версии символов _not_ выражаются в виде строк.objcopy просто не работает на них - версии выражаются в справочной таблице, которую objcopy 2.20.50 не пытается изменить. Когда-либо. Там _is_ символ «по умолчанию», который можно изменить таким образом - «symbol @@ 1.2.3» можно изменить. – Otheus

 Смежные вопросы

  • Нет связанных вопросов^_^