Переопределение динамического пути компоновщика? [Дубликат]

Обратите внимание, что команды React и Redux обычно препятствуют использованию декораторов. Вместо этого в этом случае вы должны использовать функцию connect() как функцию:

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
116
задан dogbane 11 May 2009 в 09:20
поделиться

9 ответов

Очень возможно иметь несколько версий glibc в одной и той же системе (мы делаем это каждый день).

Однако вам нужно знать, что glibc состоит из множества частей (200 + разделяемых библиотек) которые все должны совпадать. Одна из частей - ld-linux.so.2, а должна соответствовать libc.so.6, или вы увидите ошибки, которые видите.

Абсолютный путь к ld-linux.so.2 жестко закодирован в исполняемый файл во время соединения и не может быть легко изменен после завершения связи.

Чтобы создать исполняемый файл, который будет работать с новым glibc , сделайте следующее:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

Опция компоновщика -rpath сделает загрузчик времени выполнения для поиска библиотек в /path/to/newglibc (так что вам не нужно было бы устанавливать LD_LIBRARY_PATH перед запуском), и параметр -dynamic-linker будет «испечь» путь, чтобы исправить ld-linux.so.2 в приложении.

Если вы не можете повторно подключить приложение myapp (например, потому что это сторонний двоичный файл), не все потеряно, но становится сложнее. Одно из решений - установить для него подходящую среду chroot. Другая возможность - использовать rtldi и двоичный редактор .

174
ответ дан Employed Russian 25 August 2018 в 10:53
поделиться
  • 1
    Обратите внимание, что -Wl,--dynamic-linker=file (принимает два '-') работает только при компиляции для исполняемых файлов ELF. Проверьте /sbin/ldconfig -p | grep ld – Tom 28 May 2012 в 15:08
  • 2
    Теперь вы можете использовать удобную утилиту patchelf ( nixos.org/patchelf.html ), которая позволяет вам изменять rpath и интерпретатор уже скомпилированного ELF. – Michael Pankov 13 February 2013 в 14:14
  • 3
    Стоит отметить, что указание пути к новому glibc с использованием -Wl,--rpath, а не LD_LIBRARY_PATH может быть важным по причинам, отличным от удобства: если программа запускает дочерние процессы, значение LD_LIBRARY_PATH обычно наследуется ими, но если они также не скомпилированы для использования нового glibc (например, если они представляют собой двоичные файлы, например bash), они не будут запускаться. – HighCommander4 5 June 2016 в 02:22
  • 4
    Другим вариантом является запуск нового ld.so напрямую, передача его двоичной программы в качестве параметра; это эффективно заменит ld.so без необходимости перекомпиляции программы: /path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp – maximk 14 September 2016 в 11:09

Прежде всего, самая важная зависимость каждой динамически связанной программы - это компоновщик. Все библиотеки должны соответствовать версии компоновщика.

Давайте возьмем простой пример: у меня есть система новостей ubuntu, в которой я запускаю некоторую программу (в моем случае это компилятор D - ldc2). Я хотел бы запустить его на старой CentOS, но из-за старой библиотеки glibc это невозможно. Я получил

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

Мне нужно скопировать все зависимости от ubuntu до centos. Правильный метод следующий:

Сначала давайте проверим все зависимости:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

linux-vdso.so.1 не является реальной библиотекой, и нам не нужно заботиться об этом.

/lib64/ld-linux-x86-64.so.2 является компоновщиком, который используется linux do, связывает исполняемый файл со всеми динамическими библиотеками.

Остальные файлы являются реальными библиотеками, и все они вместе с компоновщиком должны быть скопированы где-то в центрах.

Предположим, что все библиотеки и компоновщики находятся в каталоге «/ mylibs».

ld-linux-x86-64.so.2 - как я уже сказал, - это компоновщик. Это не динамическая библиотека, а статический исполняемый файл. Вы можете запустить его и увидеть, что у него даже есть некоторые параметры, например, -library-path (я вернусь к нему).

В linux динамически связанная программа может быть отправлена ​​только по ее имени, например

/bin/ldc2

Linux загружает такую ​​программу в ОЗУ и проверяет, какой компоновщик установлен для нее. Обычно в 64-битной системе это /lib64/ld-linux-x86-64.so.2 (в вашей файловой системе это символическая ссылка на реальный исполняемый файл). Затем linux запускает компоновщик и загружает динамические библиотеки.

Вы также можете немного изменить это и сделать такой трюк:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

Это метод принудительного использования linux конкретный линкер.

И теперь мы можем вернуться к упомянутому ранее параметру -library-path

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

Он запустит ldc2 и загрузит динамические библиотеки из /mylibs.

Это метод вызова исполняемого файла с выбранными (не системными) библиотеками.

4
ответ дан Arkadiusz Rychliński 25 August 2018 в 10:53
поделиться
  • 1
    Я скомпилировал программу на RH7 и вам нужно запустить ее на RH6. Я не хотел создавать новый исполняемый файл или использовать patchelf, поэтому это отличная альтернатива. – Mark Rajcok 22 January 2018 в 17:05

Когда я хотел запустить Chrome-браузер в точном соответствии с Ubuntu (glibc-2.15), я получил (типичное) сообщение «... libc.so.6: version« GLIBC_2.19 »не найден ...» , Я считал, что файлы не нужны постоянно, но только для начала. Поэтому я собрал файлы, необходимые для браузера и sudo, и создал среду mini-glibc-2.19, запустил браузер, а затем снова скопировал исходные файлы. Необходимые файлы находятся в ОЗУ, а исходный glibc - один и тот же.

as root
the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

/glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so
/glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so
/glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so
/glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so

mkdir -p /glibc-2.15/i386-linux-gnu

/glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so)
/glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so)
/glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so)
/glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so)

сценарий для запуска браузера:

#!/bin/sh
sudo cp -r /glibc-2.19/* /lib
/path/to/the/browser &
sleep 1
sudo cp -r /glibc-2.15/* /lib
sudo rm -r /lib/i386-linux-gnu/*-2.19.so
0
ответ дан dudu 25 August 2018 в 10:53
поделиться

Вы можете использовать Nix http://nixos.org/nix/ ?

Nix поддерживает многопользовательское управление пакетами: несколько пользователей могут совместно использовать общий Nix хранить надежно, не нужно иметь права root для установки программного обеспечения, а также устанавливать и использовать разные версии пакета.

6
ответ дан Igor 25 August 2018 в 10:53
поделиться
  • 1
    Спасибо Игорю за то, что он научил меня Nix. Похоже, замечательная идея! :-) – marco.m 9 October 2014 в 11:08

Этот вопрос старый, другие ответы старые. Ответ «Ответственный русский» очень хорош и информативен, но он работает только в том случае, если у вас есть исходный код. Если вы этого не сделаете, альтернативы тогда были очень сложными. К счастью, в наше время у нас есть простое решение этой проблемы (как прокомментировано в одном из его ответов), используя patchelf . Все, что вам нужно сделать, это:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

И после этого вы можете просто выполнить свой файл:

$ ./myapp

Не нужно chroot или вручную редактировать двоичные файлы, к счастью , Но не забудьте сделать резервную копию своего двоичного файла, прежде чем исправлять его, если вы не уверены, что делаете, потому что он изменяет ваш двоичный файл. После этого вы не сможете восстановить старый путь к интерпретатору / rpath. Если это не сработает, вам нужно будет исправлять его до тех пор, пока не найдете путь, который действительно будет работать ... Ну, это не должен быть процесс проб и ошибок. Например, в примере OP ему понадобился GLIBC_2.3, поэтому вы можете легко найти, какая lib предоставляет эту версию, используя strings:

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

Теоретически первый grep пуст, потому что система libc не имеет требуемой версии, а второй должен вывести GLIBC_2.3, потому что он использует версию myapp, поэтому мы знаем, что мы можем patchelf использовать наш бинарный путь.

Когда вы пытаетесь запустить двоичный файл в Linux, двоичный файл пытается загрузить компоновщик, затем библиотеки, и все они должны быть в пути и / или в нужном месте. Если ваша проблема связана с компоновщиком, и вы хотите узнать, какой путь ищет ваш бинарный файл, вы можете узнать с помощью этой команды:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

Если ваша проблема связана с libs, команды, которые будут дайте вам используемые libs:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Это приведет к отображению библиотек, которые нужны вашим двоичным файлам, но вы, вероятно, уже знаете проблемные, поскольку они уже дают ошибки, как в случае OP.

«patchelf» работает для множества различных проблем, с которыми вы можете столкнуться при попытке запустить программу, связанную с этими двумя проблемами. Например, если вы получаете: ELF file OS ABI invalid, это может быть исправлено установкой нового загрузчика (часть --set-interpreter команды), поскольку я объясняю здесь здесь . Другой пример - проблема получения No such file or directory при запуске файла, который есть и исполняемый, например здесь . В этом конкретном случае OP отсутствовала ссылка на загрузчика, но, возможно, в вашем случае у вас нет доступа root и не может создать ссылку. Настройка нового интерпретатора решит вашу проблему.

Спасибо. Занимался русским и Майклом Панковым за понимание и решение!

15
ответ дан msb 25 August 2018 в 10:53
поделиться
  • 1
    Это было очень полезно! Я исправил двоичный код python, чтобы использовать новый glibc для tensorflow – faizan 22 July 2017 в 16:53
  • 2
    Это опрятное решение (ранее я не знал о patchelf), но фраза «Нет необходимости ... редактировать двоичные файлы»; может немного ввести в заблуждение (поскольку вы фактически редактируете свои двоичные файлы). – larsks 4 December 2017 в 02:17
  • 3
    Там исправлено. ;) – msb 4 December 2017 в 05:31
  • 4
    Действительно полезная утилита! Спасибо! Хотя мне удалось получить ошибку сегментации через несколько часов после того, как вы вручную разрешили зависимости, а затем исправить все, чтобы локально установить хром без прав администратора ... – G. Bergeron 6 June 2018 в 01:05
  • 5
    Это должен быть принятый ответ. – fgiraldeau 17 August 2018 в 20:50

«Занятый русский» - один из лучших ответов, и я думаю, что любой другой предлагаемый ответ может не сработать. Причина в том, что, когда приложение впервые создано, все его API-интерфейсы, которые ему нужны, разрешаются во время компиляции. Использование «ldd» u может видеть все статически связанные зависимости:

ldd /usr/lib/firefox/firefox
    linux-vdso.so.1 =>  (0x00007ffd5c5f0000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000)

Но во время выполнения firefox также загружает многие другие динамические библиотеки, например (для firefox) есть много «glib» -мещенных библиотек (хотя статическая связь там отсутствует):

 /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2
 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0
 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2

Много раз вы можете видеть, что имена одной версии являются софт-связными в другую версию. Например:

lrwxrwxrwx 1 root root     23 Dec 21  2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2
-rw-r--r-- 1 root root 160832 Mar  1  2013 libdbus-glib-1.so.2.2.2

Это означает, что в одной системе существует различная версия «библиотек», что не является проблемой, так как это один и тот же файл, и это обеспечит совместимость, когда приложения имеют несколько зависимостей версий.

Таким образом, на системном уровне все библиотеки почти взаимозависимы друг с другом, и просто изменение приоритета загрузки библиотек с помощью LD_PRELOAD или LD_LIBRARY_PATH не поможет - даже если он может загружаться, время выполнения может все еще сбой .

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

Лучшей альтернативой является chroot (кратко упоминается ER) : но для этого вам нужно будет воссоздать всю среду, в которой выполняется исходный двоичный код - обычно начиная с / lib, / usr / lib /, / usr / lib / x86 и т. д. Вы можете использовать «Buildroot» или YoctoProject , или просто tar из существующей среды Distro. (например, Fedora / Suse и т. д.).

1
ответ дан Peter Teoh 25 August 2018 в 10:53
поделиться

Используйте LD_PRELOAD: выложите свою библиотеку где-нибудь из каталогов man lib и запустите:

LD_PRELOAD='mylibc.so anotherlib.so' program

Смотрите: статья Википедии

17
ответ дан PiedPiper 25 August 2018 в 10:53
поделиться
  • 1
    хороший улов, спасибо – clevertension 19 January 2017 в 06:04
  • 2
    подумал, что это будет хорошим обходным решением для сложного Makefile, но для меня это не сработало – galactica 22 May 2017 в 22:43
  • 3
    это особенно полезно, если нет исходных двоичных данных. – coder 6 August 2017 в 05:53
  • 4
    um ... я был неправ, мне кажется, что мне нужно rpath ld-linux.so to / path / to / new / lib / frist при компиляции источника и amp; соединение – coder 6 August 2017 в 06:59

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

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

1
ответ дан rsarro 25 August 2018 в 10:53
поделиться

Я не уверен, что вопрос по-прежнему актуальный, но есть еще один способ решить проблему: Docker. Можно установить почти пустой контейнер Source Distribution (Распространение, используемый для разработки), и скопировать файлы в Container. Таким образом, вам не нужно создавать файловую систему, необходимую для chroot.

1
ответ дан user1396055 25 August 2018 в 10:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: