Как сделать Unix бинарным автономным? - PullRequest
10 голосов
/ 15 июля 2011

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

В моем случае обе машины имеют одинаковую архитектуру, одно и то же ядро ​​Ubuntu, но целевая машина не имеет make и имеет неправильную версию файлов в /lib и /usr

Одна из моих идей заключалась в том, чтобы использовать chroot и воссоздать подмножество файловой системы, которую использует двоичный файл, возможно, используя strace, чтобы выяснить, что ему нужно. Есть ли инструмент, который делает это уже?

Для потомков вот как я выясняю, какие файлы открывает процесс

#!/usr/bin/python
# source of trace_fileopen.py
# Runs command and prints all files that have been successfully opened with mode O_RDONLY
# example: trace_fileopen.py ls -l
import re, sys, subprocess, os

if __name__=='__main__':
  strace_fn = '/tmp/strace.out'
  strace_re = re.compile(r'([^(]+?)\((.*)\)\s*=\s*(\S+?)\s+(.*)$')

  cmd = sys.argv[1]
  nowhere = open('/dev/null','w')#
  p = subprocess.Popen(['strace','-o', strace_fn]+sys.argv[1:], stdout=nowhere, stderr=nowhere)
  sts = os.waitpid(p.pid, 0)[1]

  output = []
  for line in open(strace_fn):
    # ignore lines like --- SIGCHLD (Child exited) @ 0 (0) ---
    if not strace_re.match(line):
      continue
    (function,args,returnval,msg) = strace_re.findall(line)[0]
    if function=='open' and returnval!='-1':
      (fname,mode)=args.split(',',1)
      if mode.strip()=='O_RDONLY':
        if fname.startswith('"') and fname.endswith('"') and len(fname)>=2:
          fname = fname[1:-1]
        output.append(fname)
  prev_line = ""
  for line in sorted(output):
    if line==prev_line:
      continue
    print line
    prev_line = line

Обновление Проблема с решениями LD_LIBRARY_PATH заключается в том, что /lib жестко запрограммирован в интерпретаторе и имеет приоритет над LD_LIBRARY_PATH, поэтому собственные версии будут загружаться первыми. Интерпретатор жестко закодирован в двоичный файл. Один из подходов может заключаться в исправлении интерпретатора и запуске бинарного файла как patched_interpreter mycommandline Проблема заключается в том, что когда mycommandline начинается с java, это не работает, потому что Java устанавливает LD_LIBRARY_PATH и перезапускает себя, что приводит к старый переводчик. Решение, которое сработало для меня, состояло в том, чтобы открыть двоичный файл в текстовом редакторе, найти интерпретатор (/lib/ld-linux-x86-64.so.2) и заменить его на путь такой же длины к исправленному интерпретатору

Ответы [ 3 ]

4 голосов
/ 18 июля 2011

Как уже упоминалось, статическое связывание является одним из вариантов.За исключением статического связывания с glibc, с каждым выпуском все больше ломается (извините, никаких ссылок; только мой опыт).

Ваша идея chroot, вероятно, излишня.

Решение для большинства коммерческих продуктовЯ использую, насколько я могу судить, чтобы сделать их «приложение» сценарием оболочки, который устанавливает LD_LIBRARY_PATH, а затем запускает фактический исполняемый файл.Что-то вроде этого:

#!/bin/sh
here=`dirname "$0"`
export LD_LIBRARY_PATH="$here"/lib
exec "$here"/bin/my_app "$@"

Затем вы просто копируете копию всех соответствующих файлов .so в lib/, помещаете свой исполняемый файл в bin/, помещаете скрипт в . и отправляетевсе дерево.

(чтобы быть достойным производства, правильно добавьте "$here"/lib к LD_LIBRARY_PATH, если оно не пустое и т. д.)

[править, чтобы идти с обновлением]

Я думаю, вы можете быть озадачены тем, что жестко запрограммировано, а что нет.ld-linux-x86-64.so.2 - это сам динамический компоновщик;и вы правы, что его путь жестко запрограммирован в заголовке ELF.Но другие библиотеки не жестко закодированы;их ищет динамический компоновщик, который будет соблюдать LD_LIBRARY_PATH.

Если вам действительно нужен другой файл ld-linux.so, вместо исправления заголовка ELF, просто запустите сам динамический компоновщик:

/path/to/my-ld-linux.so my_program <args>

Это будет использовать ваш компоновщик вместо того, который указан в заголовке ELF.

Исправление самого исполняемого файла - зло.Пожалуйста, подумайте о бедняке, который должен поддерживать ваши вещи после того, как вы продолжите ... Никто не будет ожидать, что вы взломали заголовок ELF вручную. Кто угодно может прочитать, что делает скрипт оболочки.

Только мои 0,02 доллара.

2 голосов
/ 23 июля 2011

Есть CDE немного программного обеспечения, разработанного для того, чтобы делать именно то, что вы хотите. Вот технический разговор Google об этом http://www.youtube.com/watch?v=6XdwHo1BWwY

2 голосов
/ 15 июля 2011

Почти наверняка есть лучшие ответы, но вы можете узнать, какие библиотеки нужны двоичному файлу, с помощью команды ldd (пример для двоичного файла ls):

$ ldd /bin/ls
linux-vdso.so.1 =>  (0x00007ffffff18000)
librt.so.1 => /lib/librt.so.1 (0x00007f5ae565c000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00007f5ae543e000)
libacl.so.1 => /lib/libacl.so.1 (0x00007f5ae5235000)
libc.so.6 => /lib/libc.so.6 (0x00007f5ae4eb2000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007f5ae4c95000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5ae588b000)
libdl.so.2 => /lib/libdl.so.2 (0x00007f5ae4a90000)
libattr.so.1 => /lib/libattr.so.1 (0x00007f5ae488b000)

Как только вы это получитеВы можете делать копии и помещать их в нужные места на целевой машине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...