7

Мне нужен более новый Glibc, чем в моей системе, для бинарного файла, который я хочу запустить. Так что у меня есть каталог /my_libs с большинством lib-файлов из недавней Ubuntu, включая новый Glibc (libc.so.6).

Теперь я экспортировал LD_LIBRARY_PATH=/my_libs:$LD_LIBRARY_PATH и пытаюсь запустить мой исполняемый файл. Это рухнет с SEGFAULT. Фактически, каждый двоичный файл теперь падает с SEGFAULT (даже простые вещи, такие как /bin/ls). Поэтому я предполагаю, что между разными библиотеками из /my_libs и моей основной системой существует некоторая путаница . Я проследил с помощью LD_DEBUG=libs (или LD_DEBUG=all) и разрешил все, кроме ld-linux-x86-64.so.2 . Что бы я ни делал, он всегда использовал /lib64/ld-linux-x86-64.so.2 а не /my_libs/ld-linux-x86-64.so.2 .

Есть ли способ установить путь для ld-linux? Как я понял, эта библиотека, которая также является исполняемым файлом, всегда используется для запуска любой программы, и моя среда использует /lib64/ld-linux-x86-64.so.2 .

Если я непосредственно запускаю /my_libs/ld-linux-x86-64.so.2 /bin/ls , это работает. Я также могу выполнить свой новый двоичный файл таким образом - я просто должен быть уверен, что все библиотеки предоставлены в /my_libs или что библиотеки из системы совместимы.

Итак, что я могу сделать, чтобы простой вызов /bin/ls напрямую использовал /my_libs/ld-linux-x86-64.so.2?

Некоторая связанная с этим дискуссия здесь.

Обратите внимание, что я не хочу исправлять /bin/ls или другие двоичные файлы, чтобы это работало.

1 ответ1

7

Tl:dr: Если вам нужно продолжать использовать несколько версий libc, как это делают многие из нас, то ключевой утилитой для использования является PatchElf.

Обычно, если все, что вам нужно, это принудительно использовать собственную версию интерпретатора программы при создании собственной программы, все, что вам нужно сделать, это скомпилировать следующие параметры:

gcc -Wl,-dynamic-linker,/my/lib/ld-linux.so.2 ...

Но это не работает со сторонними утилитами и с некоторыми общими объектами, которые, тем не менее, выполняются сами по себе, поэтому вы вызываете patchelf для данной программы ELF следующим образом:

patchelf --set-interpreter /my/lib/my-ld-linux.so.2 someprogram

Причина, по которой это не просто вопрос редактирования с помощью шестнадцатеричного редактора старого исполняемого файла и замены старого адреса интерпретатора новым, заключается в том, что эти два значения не обязательно должны быть одинаковой длины; patchelf заботится о расширении вашего исполняемого файла для вас.

Вы также можете изменить переменную rpath следующим образом:

patchelf --set-rpath /my_libs:$LD_LIBRARY_PATH someprogram 

Я считаю, что это намного удобнее, чем использование обычных оболочек для команд с LD_LIBRARY_PATH.

Что касается execve, это должен быть почти самый фундаментальный системный вызов в Unix: execve(имя файла) выполняет заданное имя файла. Например, ваша оболочка выполняет команду с помощью вызова семейства execve: сначала она разветвляется, а затем дочерний процесс генерирует команду execve (ls, cd, ... вы ее называете). Большинству программ нужны динамически связанные библиотеки, например, для ls:

$ ldd $(which ls)
    linux-vdso.so.1 =>  (0x00007ffe3b0e7000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f1423dda000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1423a11000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f14237a0000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f142359c000)
    /lib64/ld-linux-x86-64.so.2 (0x0000563800043000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f142337f000)

Когда вы загружаете ls, сначала используется не двоичная обычная точка входа, а вместо этого ld-linux : он заботится о загрузке всех неразрешенных необходимых библиотек, а затем передает управление реальному приложению, в этом случае ls дело. Это делается путем выполнения файла программы.

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

    $ readelf -l /bin/ls

    Elf file type is EXEC (Executable file)
    Entry point 0x4049a0
    There are 9 program headers, starting at offset 64

    Program Headers:
      Type           Offset             VirtAddr           PhysAddr
                     FileSiz            MemSiz              Flags  Align
      PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                     0x00000000000001f8 0x00000000000001f8  R E    8
      INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                     0x000000000000001c 0x000000000000001c  R      1
          [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
    ...........................

(акцент мой ...).

РЕДАКТИРОВАТЬ: отличное обсуждение одним из авторов системного вызова execveat можно найти здесь, а соответствующий код ядра здесь. Код показывает, что системная переменная не читается, и процедура load_elf_binary просматривает интерпретатор программы PT_INTERP.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .